summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AconfigFlags.bp4
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java4
-rw-r--r--api/StubLibraries.bp1
-rw-r--r--api/api.go5
-rwxr-xr-xcmds/am/am.sh3
-rw-r--r--cmds/uinput/README.md10
-rw-r--r--core/api/current.txt17
-rw-r--r--core/api/system-current.txt59
-rw-r--r--core/api/test-current.txt53
-rw-r--r--core/java/android/app/Activity.java15
-rw-r--r--core/java/android/app/ActivityOptions.java3
-rw-r--r--core/java/android/app/ActivityThread.java34
-rw-r--r--core/java/android/app/ApplicationStartInfo.java8
-rw-r--r--core/java/android/app/DisabledWallpaperManager.java7
-rw-r--r--core/java/android/app/DreamManager.java15
-rw-r--r--core/java/android/app/INotificationManager.aidl1
-rw-r--r--core/java/android/app/Notification.java171
-rw-r--r--core/java/android/app/NotificationManager.java95
-rw-r--r--core/java/android/app/PropertyInvalidatedCache.java38
-rw-r--r--core/java/android/app/WallpaperManager.java59
-rw-r--r--core/java/android/app/notification.aconfig17
-rw-r--r--core/java/android/app/supervision/ISupervisionAppService.aidl25
-rw-r--r--core/java/android/app/supervision/SupervisionAppService.java56
-rw-r--r--core/java/android/app/supervision/flags.aconfig8
-rw-r--r--core/java/android/app/wallpaper.aconfig8
-rw-r--r--core/java/android/app/wallpaper/WallpaperDescription.java8
-rw-r--r--core/java/android/companion/virtual/VirtualDevice.java13
-rw-r--r--core/java/android/companion/virtual/VirtualDeviceInternal.java15
-rw-r--r--core/java/android/companion/virtual/VirtualDeviceManager.java24
-rw-r--r--core/java/android/companion/virtual/VirtualDeviceParams.java60
-rw-r--r--core/java/android/companion/virtual/flags/flags.aconfig8
-rw-r--r--core/java/android/content/Intent.java38
-rw-r--r--core/java/android/content/pm/LauncherApps.java6
-rw-r--r--core/java/android/credentials/flags.aconfig10
-rw-r--r--core/java/android/database/sqlite/SQLiteOpenHelper.java133
-rw-r--r--core/java/android/database/sqlite/flags.aconfig9
-rw-r--r--core/java/android/hardware/contexthub/HubEndpoint.java291
-rw-r--r--core/java/android/hardware/devicestate/feature/flags.aconfig14
-rw-r--r--core/java/android/hardware/display/DisplayManager.java1
-rw-r--r--core/java/android/hardware/display/VirtualDisplayConfig.java4
-rw-r--r--core/java/android/hardware/input/KeyGestureEvent.java34
-rw-r--r--core/java/android/hardware/input/VirtualStylus.java3
-rw-r--r--core/java/android/hardware/input/VirtualStylusButtonEvent.java4
-rw-r--r--core/java/android/hardware/input/VirtualStylusConfig.java4
-rw-r--r--core/java/android/hardware/input/VirtualStylusMotionEvent.java4
-rw-r--r--core/java/android/hardware/input/input_framework.aconfig7
-rw-r--r--core/java/android/os/CombinedMessageQueue/MessageQueue.java7
-rw-r--r--core/java/android/os/IpcDataCache.java70
-rw-r--r--core/java/android/os/LegacyMessageQueue/MessageQueue.java7
-rw-r--r--core/java/android/os/Looper.java42
-rw-r--r--core/java/android/os/PowerManagerInternal.java6
-rw-r--r--core/java/android/os/TEST_MAPPING26
-rw-r--r--core/java/android/os/health/SystemHealthManager.java12
-rw-r--r--core/java/android/permission/PermissionManager.java5
-rw-r--r--core/java/android/provider/Settings.java28
-rw-r--r--core/java/android/security/flags.aconfig9
-rw-r--r--core/java/android/service/dreams/IDreamManager.aidl2
-rw-r--r--core/java/android/service/notification/StatusBarNotification.java63
-rw-r--r--core/java/android/service/settings/preferences/SettingsPreferenceValue.java103
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java68
-rw-r--r--core/java/android/text/Layout.java6
-rw-r--r--core/java/android/view/InsetsAnimationControlImpl.java19
-rw-r--r--core/java/android/view/SurfaceControl.java4
-rw-r--r--core/java/android/view/SurfaceView.java2
-rw-r--r--core/java/android/view/ViewRootImpl.java20
-rw-r--r--core/java/android/view/WindowManagerGlobal.java4
-rw-r--r--core/java/android/widget/Magnifier.java5
-rw-r--r--core/java/android/window/TaskFragmentOperation.java11
-rw-r--r--core/java/android/window/TransitionInfo.java2
-rw-r--r--core/java/android/window/flags/lse_desktop_experience.aconfig17
-rw-r--r--core/java/android/window/flags/windowing_frontend.aconfig35
-rw-r--r--core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java3
-rw-r--r--core/java/com/android/internal/accessibility/util/ShortcutUtils.java45
-rw-r--r--core/java/com/android/internal/app/IntentForwarderActivity.java15
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java7
-rw-r--r--core/java/com/android/internal/content/NativeLibraryHelper.java10
-rw-r--r--core/java/com/android/internal/jank/Cuj.java16
-rw-r--r--core/java/com/android/internal/os/RuntimeInit.java4
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java40
-rw-r--r--core/java/com/android/internal/widget/NotificationProgressBar.java28
-rw-r--r--core/jni/com_android_internal_content_NativeLibraryHelper.cpp38
-rw-r--r--core/jni/fd_utils.cpp3
-rw-r--r--core/res/AndroidManifest.xml22
-rw-r--r--core/res/res/values-af/strings.xml27
-rw-r--r--core/res/res/values-am/strings.xml27
-rw-r--r--core/res/res/values-ar/strings.xml27
-rw-r--r--core/res/res/values-as/strings.xml26
-rw-r--r--core/res/res/values-az/strings.xml27
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml27
-rw-r--r--core/res/res/values-be/strings.xml27
-rw-r--r--core/res/res/values-bg/strings.xml27
-rw-r--r--core/res/res/values-bn/strings.xml27
-rw-r--r--core/res/res/values-bs/strings.xml27
-rw-r--r--core/res/res/values-ca/strings.xml27
-rw-r--r--core/res/res/values-cs/strings.xml37
-rw-r--r--core/res/res/values-da/strings.xml27
-rw-r--r--core/res/res/values-de/strings.xml27
-rw-r--r--core/res/res/values-el/strings.xml27
-rw-r--r--core/res/res/values-en-rAU/strings.xml27
-rw-r--r--core/res/res/values-en-rCA/strings.xml23
-rw-r--r--core/res/res/values-en-rGB/strings.xml27
-rw-r--r--core/res/res/values-en-rIN/strings.xml27
-rw-r--r--core/res/res/values-es-rUS/strings.xml27
-rw-r--r--core/res/res/values-es/strings.xml27
-rw-r--r--core/res/res/values-et/strings.xml27
-rw-r--r--core/res/res/values-eu/strings.xml27
-rw-r--r--core/res/res/values-fa/strings.xml31
-rw-r--r--core/res/res/values-fi/strings.xml27
-rw-r--r--core/res/res/values-fr-rCA/strings.xml27
-rw-r--r--core/res/res/values-fr/strings.xml27
-rw-r--r--core/res/res/values-gl/strings.xml27
-rw-r--r--core/res/res/values-gu/strings.xml27
-rw-r--r--core/res/res/values-hi/strings.xml26
-rw-r--r--core/res/res/values-hr/strings.xml27
-rw-r--r--core/res/res/values-hu/strings.xml27
-rw-r--r--core/res/res/values-hy/strings.xml27
-rw-r--r--core/res/res/values-in/strings.xml27
-rw-r--r--core/res/res/values-is/strings.xml27
-rw-r--r--core/res/res/values-it/strings.xml29
-rw-r--r--core/res/res/values-iw/strings.xml151
-rw-r--r--core/res/res/values-ja/strings.xml26
-rw-r--r--core/res/res/values-ka/strings.xml26
-rw-r--r--core/res/res/values-kk/strings.xml27
-rw-r--r--core/res/res/values-km/strings.xml27
-rw-r--r--core/res/res/values-kn/strings.xml27
-rw-r--r--core/res/res/values-ko/strings.xml27
-rw-r--r--core/res/res/values-ky/strings.xml27
-rw-r--r--core/res/res/values-lo/strings.xml27
-rw-r--r--core/res/res/values-lt/strings.xml27
-rw-r--r--core/res/res/values-lv/strings.xml27
-rw-r--r--core/res/res/values-mk/strings.xml27
-rw-r--r--core/res/res/values-ml/strings.xml26
-rw-r--r--core/res/res/values-mn/strings.xml27
-rw-r--r--core/res/res/values-mr/strings.xml27
-rw-r--r--core/res/res/values-ms/strings.xml26
-rw-r--r--core/res/res/values-my/strings.xml37
-rw-r--r--core/res/res/values-nb/strings.xml27
-rw-r--r--core/res/res/values-ne/strings.xml27
-rw-r--r--core/res/res/values-nl/strings.xml27
-rw-r--r--core/res/res/values-or/strings.xml27
-rw-r--r--core/res/res/values-pa/strings.xml27
-rw-r--r--core/res/res/values-pl/strings.xml26
-rw-r--r--core/res/res/values-pt-rBR/strings.xml29
-rw-r--r--core/res/res/values-pt-rPT/strings.xml26
-rw-r--r--core/res/res/values-pt/strings.xml29
-rw-r--r--core/res/res/values-ro/strings.xml27
-rw-r--r--core/res/res/values-ru/strings.xml27
-rw-r--r--core/res/res/values-si/strings.xml37
-rw-r--r--core/res/res/values-sk/strings.xml27
-rw-r--r--core/res/res/values-sl/strings.xml27
-rw-r--r--core/res/res/values-sq/strings.xml37
-rw-r--r--core/res/res/values-sr/strings.xml27
-rw-r--r--core/res/res/values-sv/strings.xml27
-rw-r--r--core/res/res/values-sw/strings.xml27
-rw-r--r--core/res/res/values-ta/strings.xml27
-rw-r--r--core/res/res/values-te/strings.xml27
-rw-r--r--core/res/res/values-th/strings.xml27
-rw-r--r--core/res/res/values-tl/strings.xml29
-rw-r--r--core/res/res/values-tr/strings.xml27
-rw-r--r--core/res/res/values-uk/strings.xml37
-rw-r--r--core/res/res/values-ur/strings.xml29
-rw-r--r--core/res/res/values-uz/strings.xml27
-rw-r--r--core/res/res/values-vi/strings.xml27
-rw-r--r--core/res/res/values-zh-rCN/strings.xml27
-rw-r--r--core/res/res/values-zh-rHK/strings.xml27
-rw-r--r--core/res/res/values-zh-rTW/strings.xml27
-rw-r--r--core/res/res/values-zu/strings.xml27
-rw-r--r--core/res/res/values/attrs.xml9
-rw-r--r--core/res/res/values/config.xml18
-rw-r--r--core/res/res/values/public-staging.xml6
-rw-r--r--core/res/res/values/symbols.xml8
-rw-r--r--core/tests/coretests/src/android/app/NotificationManagerTest.java44
-rw-r--r--core/tests/coretests/src/android/app/NotificationTest.java77
-rw-r--r--core/tests/coretests/src/android/os/SystemHealthManagerUnitTest.java155
-rw-r--r--core/tests/coretests/src/android/provider/SettingsProviderTest.java48
-rw-r--r--core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java33
-rw-r--r--core/tests/coretests/src/android/text/LayoutTest.java49
-rw-r--r--core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java112
-rw-r--r--core/tests/coretests/src/com/android/internal/widget/NotificationProgressBarTest.java179
-rw-r--r--data/etc/preinstalled-packages-platform.xml7
-rw-r--r--graphics/java/android/graphics/BLASTBufferQueue.java6
-rw-r--r--graphics/java/android/graphics/OWNERS4
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java11
-rw-r--r--libs/WindowManager/Shell/Android.bp2
-rw-r--r--libs/WindowManager/Shell/AndroidManifest.xml2
-rw-r--r--libs/WindowManager/Shell/aconfig/Android.bp1
-rw-r--r--libs/WindowManager/Shell/aconfig/automotive.aconfig11
-rw-r--r--libs/WindowManager/Shell/aconfig/multitasking.aconfig14
-rw-r--r--libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt2
-rw-r--r--libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt2
-rw-r--r--libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskTest.kt2
-rw-r--r--libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/FakeBubbleFactory.kt2
-rw-r--r--libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt5
-rw-r--r--libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt2
-rw-r--r--libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt2
-rw-r--r--libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/common/TestShellExecutor.kt (renamed from libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/TestShellExecutor.kt)4
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_bar_manage_education.xml2
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_bar_stack_education.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-iw/strings.xml24
-rw-r--r--libs/WindowManager/Shell/res/values-te/strings.xml2
-rw-r--r--libs/WindowManager/Shell/shared/Android.bp1
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java4
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleAnythingFlagHelper.java48
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/appzoomout/AppZoomOutController.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/automotive/AutoTaskStackControllerImpl.kt10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt227
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt49
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt44
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java55
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsShellCommandHandler.kt51
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/FocusTransitionObserver.java76
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt293
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java5
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/CloseAllAppsWithBackNavigationLandscape.kt51
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/CloseAllAppsWithBackNavigationPortrait.kt48
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/EnterDesktopWithDragExistingWindowsTest.kt27
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithBackNavigation.kt73
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithAppHandleMenuExistingWindows.kt70
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDragExistingWindows.kt74
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenUnlimitedApps.kt11
-rw-r--r--libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/CopyContentInSplit.kt4
-rw-r--r--libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/DismissSplitScreenByDivider.kt4
-rw-r--r--libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/DismissSplitScreenByGoHome.kt4
-rw-r--r--libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/DragDividerToResize.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/RecentTasksUtils.kt27
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt54
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java21
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTransitionStateTest.java18
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java20
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java30
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java121
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt611
-rw-r--r--libs/androidfw/ApkParsing.cpp10
-rw-r--r--libs/androidfw/include/androidfw/ApkParsing.h2
-rw-r--r--libs/androidfw/tests/ApkParsing_test.cpp26
-rw-r--r--libs/hwui/aconfig/hwui_flags.aconfig10
-rw-r--r--libs/hwui/hwui/DrawTextFunctor.h23
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp9
-rw-r--r--location/java/android/location/Geocoder.java7
-rw-r--r--media/java/android/media/MediaRoute2ProviderService.java18
-rw-r--r--media/java/android/media/quality/MediaQualityManager.java89
-rw-r--r--media/java/android/media/tv/flags/media_tv.aconfig10
-rw-r--r--media/jni/android_media_tv_Tuner.cpp26
-rw-r--r--media/tests/MediaRouter/Android.bp2
-rw-r--r--native/android/TEST_MAPPING18
-rw-r--r--native/android/libandroid.map.txt1
-rw-r--r--native/android/system_health.cpp60
-rw-r--r--native/android/tests/system_health/Android.bp66
-rw-r--r--native/android/tests/system_health/NativeSystemHealthUnitTest.cpp231
-rw-r--r--native/graphics/jni/Android.bp7
-rw-r--r--nfc-non-updatable/flags/flags.aconfig8
-rw-r--r--packages/CarrierDefaultApp/res/values-iw/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/res/values-af/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-am/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-ar/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-as/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-az/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-be/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-bg/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-bn/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-bs/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-ca/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-cs/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-da/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-de/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-el/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-en-rAU/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-en-rCA/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-en-rGB/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-en-rIN/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-es-rUS/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-es/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-et/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-eu/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-fa/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-fi/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-fr/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-gl/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-gu/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-hi/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-hr/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-hu/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-hy/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-in/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-is/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-it/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-iw/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-ja/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-ka/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-kk/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-km/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-kn/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-ko/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-ky/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-lo/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-lt/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-lv/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-mk/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-ml/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-mn/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-mr/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-ms/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-my/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-nb/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-ne/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-nl/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-or/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-pa/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-pl/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-pt/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-ro/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-ru/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-si/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-sk/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-sl/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-sq/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-sr/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-sv/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-sw/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-ta/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-te/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-th/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-tl/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-tr/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-uk/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-ur/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-uz/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-vi/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-zu/strings.xml6
-rw-r--r--packages/CrashRecovery/framework/Android.bp9
-rw-r--r--packages/CrashRecovery/services/module/java/com/android/server/RescueParty.java132
-rw-r--r--packages/CrashRecovery/services/module/java/com/android/util/ArrayUtils.java73
-rw-r--r--packages/CrashRecovery/services/module/java/com/android/util/FileUtils.java11
-rw-r--r--packages/CrashRecovery/services/module/java/com/android/util/XmlUtils.java53
-rw-r--r--packages/CredentialManager/res/values-eu/strings.xml4
-rw-r--r--packages/CredentialManager/res/values-iw/strings.xml2
-rw-r--r--packages/CredentialManager/wear/res/values-iw/strings.xml2
-rw-r--r--packages/EasterEgg/AndroidManifest.xml6
-rw-r--r--packages/EasterEgg/res/drawable/android16_patch_adaptive.xml21
-rw-r--r--packages/EasterEgg/res/drawable/android16_patch_adaptive_background.xml245
-rw-r--r--packages/EasterEgg/res/drawable/android16_patch_adaptive_foreground.xml35
-rw-r--r--packages/EasterEgg/res/drawable/android16_patch_monochrome.xml113
-rw-r--r--packages/EasterEgg/src/com/android/egg/landroid/DreamUniverse.kt2
-rw-r--r--packages/EasterEgg/src/com/android/egg/landroid/MainActivity.kt31
-rw-r--r--packages/EasterEgg/src/com/android/egg/landroid/Physics.kt24
-rw-r--r--packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt118
-rw-r--r--packages/InputDevices/res/values-af/strings.xml1
-rw-r--r--packages/InputDevices/res/values-am/strings.xml1
-rw-r--r--packages/InputDevices/res/values-ar/strings.xml2
-rw-r--r--packages/InputDevices/res/values-as/strings.xml1
-rw-r--r--packages/InputDevices/res/values-az/strings.xml1
-rw-r--r--packages/InputDevices/res/values-b+sr+Latn/strings.xml1
-rw-r--r--packages/InputDevices/res/values-be/strings.xml1
-rw-r--r--packages/InputDevices/res/values-bg/strings.xml1
-rw-r--r--packages/InputDevices/res/values-bn/strings.xml1
-rw-r--r--packages/InputDevices/res/values-bs/strings.xml1
-rw-r--r--packages/InputDevices/res/values-ca/strings.xml1
-rw-r--r--packages/InputDevices/res/values-cs/strings.xml2
-rw-r--r--packages/InputDevices/res/values-da/strings.xml1
-rw-r--r--packages/InputDevices/res/values-de/strings.xml1
-rw-r--r--packages/InputDevices/res/values-el/strings.xml1
-rw-r--r--packages/InputDevices/res/values-en-rAU/strings.xml1
-rw-r--r--packages/InputDevices/res/values-en-rCA/strings.xml1
-rw-r--r--packages/InputDevices/res/values-en-rGB/strings.xml1
-rw-r--r--packages/InputDevices/res/values-en-rIN/strings.xml1
-rw-r--r--packages/InputDevices/res/values-es-rUS/strings.xml1
-rw-r--r--packages/InputDevices/res/values-es/strings.xml1
-rw-r--r--packages/InputDevices/res/values-et/strings.xml1
-rw-r--r--packages/InputDevices/res/values-eu/strings.xml1
-rw-r--r--packages/InputDevices/res/values-fa/strings.xml1
-rw-r--r--packages/InputDevices/res/values-fi/strings.xml1
-rw-r--r--packages/InputDevices/res/values-fr-rCA/strings.xml1
-rw-r--r--packages/InputDevices/res/values-fr/strings.xml1
-rw-r--r--packages/InputDevices/res/values-gl/strings.xml1
-rw-r--r--packages/InputDevices/res/values-gu/strings.xml1
-rw-r--r--packages/InputDevices/res/values-hi/strings.xml1
-rw-r--r--packages/InputDevices/res/values-hr/strings.xml1
-rw-r--r--packages/InputDevices/res/values-hu/strings.xml1
-rw-r--r--packages/InputDevices/res/values-hy/strings.xml1
-rw-r--r--packages/InputDevices/res/values-in/strings.xml1
-rw-r--r--packages/InputDevices/res/values-is/strings.xml1
-rw-r--r--packages/InputDevices/res/values-it/strings.xml1
-rw-r--r--packages/InputDevices/res/values-iw/strings.xml2
-rw-r--r--packages/InputDevices/res/values-ja/strings.xml1
-rw-r--r--packages/InputDevices/res/values-ka/strings.xml1
-rw-r--r--packages/InputDevices/res/values-kk/strings.xml1
-rw-r--r--packages/InputDevices/res/values-km/strings.xml1
-rw-r--r--packages/InputDevices/res/values-kn/strings.xml1
-rw-r--r--packages/InputDevices/res/values-ko/strings.xml1
-rw-r--r--packages/InputDevices/res/values-ky/strings.xml1
-rw-r--r--packages/InputDevices/res/values-lo/strings.xml1
-rw-r--r--packages/InputDevices/res/values-lt/strings.xml1
-rw-r--r--packages/InputDevices/res/values-lv/strings.xml1
-rw-r--r--packages/InputDevices/res/values-mk/strings.xml1
-rw-r--r--packages/InputDevices/res/values-ml/strings.xml1
-rw-r--r--packages/InputDevices/res/values-mn/strings.xml1
-rw-r--r--packages/InputDevices/res/values-mr/strings.xml1
-rw-r--r--packages/InputDevices/res/values-ms/strings.xml1
-rw-r--r--packages/InputDevices/res/values-my/strings.xml1
-rw-r--r--packages/InputDevices/res/values-nb/strings.xml1
-rw-r--r--packages/InputDevices/res/values-ne/strings.xml1
-rw-r--r--packages/InputDevices/res/values-nl/strings.xml1
-rw-r--r--packages/InputDevices/res/values-or/strings.xml1
-rw-r--r--packages/InputDevices/res/values-pa/strings.xml1
-rw-r--r--packages/InputDevices/res/values-pl/strings.xml1
-rw-r--r--packages/InputDevices/res/values-pt-rBR/strings.xml1
-rw-r--r--packages/InputDevices/res/values-pt-rPT/strings.xml1
-rw-r--r--packages/InputDevices/res/values-pt/strings.xml1
-rw-r--r--packages/InputDevices/res/values-ro/strings.xml1
-rw-r--r--packages/InputDevices/res/values-ru/strings.xml1
-rw-r--r--packages/InputDevices/res/values-si/strings.xml2
-rw-r--r--packages/InputDevices/res/values-sk/strings.xml1
-rw-r--r--packages/InputDevices/res/values-sl/strings.xml1
-rw-r--r--packages/InputDevices/res/values-sq/strings.xml2
-rw-r--r--packages/InputDevices/res/values-sr/strings.xml1
-rw-r--r--packages/InputDevices/res/values-sv/strings.xml1
-rw-r--r--packages/InputDevices/res/values-sw/strings.xml1
-rw-r--r--packages/InputDevices/res/values-ta/strings.xml1
-rw-r--r--packages/InputDevices/res/values-te/strings.xml1
-rw-r--r--packages/InputDevices/res/values-th/strings.xml1
-rw-r--r--packages/InputDevices/res/values-tl/strings.xml1
-rw-r--r--packages/InputDevices/res/values-tr/strings.xml1
-rw-r--r--packages/InputDevices/res/values-uk/strings.xml2
-rw-r--r--packages/InputDevices/res/values-ur/strings.xml1
-rw-r--r--packages/InputDevices/res/values-uz/strings.xml2
-rw-r--r--packages/InputDevices/res/values-vi/strings.xml1
-rw-r--r--packages/InputDevices/res/values-zh-rCN/strings.xml1
-rw-r--r--packages/InputDevices/res/values-zh-rHK/strings.xml1
-rw-r--r--packages/InputDevices/res/values-zh-rTW/strings.xml1
-rw-r--r--packages/InputDevices/res/values-zu/strings.xml1
-rw-r--r--packages/PackageInstaller/res/values-kn/strings.xml2
-rw-r--r--packages/SettingsLib/CardPreference/res/drawable/settingslib_card_preference_background.xml28
-rw-r--r--packages/SettingsLib/CardPreference/res/layout/settingslib_expressive_preference_card.xml35
-rw-r--r--packages/SettingsLib/CardPreference/res/values/styles_expressive.xml4
-rw-r--r--packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt12
-rw-r--r--packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt5
-rw-r--r--packages/SettingsLib/IllustrationPreference/res/drawable/protection_background_tablet.xml27
-rw-r--r--packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml9
-rw-r--r--packages/SettingsLib/IllustrationPreference/res/values/dimens.xml3
-rw-r--r--packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java20
-rw-r--r--packages/SettingsLib/Metadata/processor/src/com/android/settingslib/metadata/PreferenceScreenAnnotationProcessor.kt10
-rw-r--r--packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt23
-rw-r--r--packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceTypes.kt2
-rw-r--r--packages/SettingsLib/SearchWidget/res/values-as/strings.xml2
-rw-r--r--packages/SettingsLib/SearchWidget/res/values-es-rUS/strings.xml2
-rw-r--r--packages/SettingsLib/SearchWidget/res/values-mk/strings.xml2
-rw-r--r--packages/SettingsLib/SearchWidget/res/values-pa/strings.xml2
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-v35/themes.xml2
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values/strings.xml2
-rw-r--r--packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt22
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt9
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt2
-rw-r--r--packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BytesFormatter.kt17
-rw-r--r--packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppStorageRepository.kt92
-rw-r--r--packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt40
-rw-r--r--packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppStorageRepositoryTest.kt94
-rw-r--r--packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt85
-rw-r--r--packages/SettingsLib/ZeroStatePreference/Android.bp1
-rw-r--r--packages/SettingsLib/ZeroStatePreference/res/layout/settingslib_expressive_preference_zerostate.xml2
-rw-r--r--packages/SettingsLib/aconfig/settingslib.aconfig10
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml16
-rw-r--r--packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/Utils.java25
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java16
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt65
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioSharingRepositoryTest.kt48
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java4
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java1
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java43
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java69
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig10
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java81
-rw-r--r--packages/Shell/res/values-iw/strings.xml6
-rw-r--r--packages/SystemUI/Android.bp3
-rw-r--r--packages/SystemUI/AndroidManifest.xml8
-rw-r--r--packages/SystemUI/OWNERS1
-rw-r--r--packages/SystemUI/accessibility/accessibilitymenu/AndroidManifest.xml5
-rw-r--r--packages/SystemUI/accessibility/accessibilitymenu/res/values-iw/strings.xml4
-rw-r--r--packages/SystemUI/aconfig/Android.bp1
-rw-r--r--packages/SystemUI/aconfig/accessibility.aconfig20
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig62
-rw-r--r--packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java12
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java4
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/ui/graphics/DrawInContainer.kt33
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt10
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt228
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt7
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt27
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalTouchableSurface.kt38
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/AmbientStatusBarSection.kt10
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/dream/ui/composable/DreamScene.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt13
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/CommunalBlueprint.kt12
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ComposableLockscreenSceneBlueprint.kt8
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/AmbientIndicationSection.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/StatusBarSection.kt5
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt46
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarouselStateLoader.kt8
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt20
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt37
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt20
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt8
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt33
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/Scene.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt15
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt12
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt11
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt31
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt13
-rw-r--r--packages/SystemUI/compose/scene/Android.bp1
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateOverlay.kt3
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt2
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt391
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt678
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt4
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt40
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt83
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt86
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt140
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt13
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/Seek.kt5
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt178
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt6
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt2
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt866
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt2
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt2
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt12
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestOverlayTransition.kt2
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestReplaceOverlayTransition.kt2
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestSceneTransition.kt3
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/SensorLocation.kt (renamed from packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorLocation.kt)26
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderClient.kt14
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt6
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/FakeCustomizationProviderClient.kt4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt3
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java3
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java134
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepositoryTest.kt94
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt9
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/composable/BouncerPredictiveBackTest.kt4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/ClipboardImageLoaderTest.kt65
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalUserActionsViewModelTest.kt7
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorTest.kt6
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt7
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt12
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSColumnsRepositoryTest.kt18
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/A11yShortcutAutoAddableListTest.kt26
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt121
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AccessibilityTilesInteractorTest.kt39
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java15
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt51
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt7
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/interactor/HearingDevicesTileDataInteractorTest.kt15
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelTest.kt20
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt51
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt70
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractorTest.kt6
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shared/customization/data/SensorLocationTest.kt36
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt92
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt32
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt7
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java228
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModelTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt28
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt35
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java5
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java40
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt41
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java48
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorTest.kt56
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt6
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.kt72
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java35
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt22
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt11
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt157
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/StatusBarOperatorNameViewModelTest.kt17
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt176
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt26
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialActionStateSaverTest.kt77
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelTest.kt16
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioSharingInteractorTest.kt49
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelTest.kt91
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelTest.kt29
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/GradientColorWallpaperTest.kt85
-rw-r--r--packages/SystemUI/res-product/values-iw/strings.xml20
-rw-r--r--packages/SystemUI/res/drawable/android16_patch_adaptive.xml21
-rw-r--r--packages/SystemUI/res/drawable/android16_patch_adaptive_background.xml245
-rw-r--r--packages/SystemUI/res/drawable/android16_patch_adaptive_foreground.xml35
-rw-r--r--packages/SystemUI/res/drawable/android16_patch_monochrome.xml113
-rw-r--r--packages/SystemUI/res/drawable/ic_media_connecting_button_container.xml45
-rw-r--r--packages/SystemUI/res/drawable/ic_media_connecting_status_container.xml199
-rw-r--r--packages/SystemUI/res/layout/qs_footer_impl.xml5
-rw-r--r--packages/SystemUI/res/layout/volume_dialog_slider.xml4
-rw-r--r--packages/SystemUI/res/layout/window_magnification_settings_view.xml3
-rw-r--r--packages/SystemUI/res/values-af/strings.xml10
-rw-r--r--packages/SystemUI/res/values-am/strings.xml10
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml11
-rw-r--r--packages/SystemUI/res/values-as/strings.xml10
-rw-r--r--packages/SystemUI/res/values-az/strings.xml10
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml10
-rw-r--r--packages/SystemUI/res/values-be/strings.xml10
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml10
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml10
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml12
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml10
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml13
-rw-r--r--packages/SystemUI/res/values-da/strings.xml12
-rw-r--r--packages/SystemUI/res/values-de/strings.xml12
-rw-r--r--packages/SystemUI/res/values-el/strings.xml10
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml10
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml7
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml10
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml10
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml10
-rw-r--r--packages/SystemUI/res/values-es/strings.xml12
-rw-r--r--packages/SystemUI/res/values-et/strings.xml12
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml12
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml10
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml10
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml10
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml10
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml10
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml16
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml10
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml10
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml10
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml14
-rw-r--r--packages/SystemUI/res/values-in/strings.xml10
-rw-r--r--packages/SystemUI/res/values-is/strings.xml10
-rw-r--r--packages/SystemUI/res/values-it/strings.xml10
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml111
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml10
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml10
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml12
-rw-r--r--packages/SystemUI/res/values-km/strings.xml10
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml10
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml12
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml10
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml10
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml10
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml10
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml10
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml10
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml10
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml10
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml10
-rw-r--r--packages/SystemUI/res/values-my/strings.xml12
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml12
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml16
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml10
-rw-r--r--packages/SystemUI/res/values-or/strings.xml12
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml14
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml12
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml14
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml14
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml14
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml10
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml10
-rw-r--r--packages/SystemUI/res/values-si/strings.xml13
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml12
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml10
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml13
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml10
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml10
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml10
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml10
-rw-r--r--packages/SystemUI/res/values-te/strings.xml10
-rw-r--r--packages/SystemUI/res/values-th/strings.xml10
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml10
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml14
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml13
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml10
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml15
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml12
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml10
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml14
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml10
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml10
-rw-r--r--packages/SystemUI/res/values/dimens.xml7
-rw-r--r--packages/SystemUI/res/values/strings.xml6
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginEnabler.java3
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java10
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java8
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LiftToActivateListener.java72
-rw-r--r--packages/SystemUI/src/com/android/systemui/KairosActivatable.kt212
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/MagnificationImpl.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogReceiver.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt60
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/composable/BouncerContainer.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingCoreStartable.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardImageLoader.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/ui/domain/interactor/ConfigurationInteractor.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/DevicePosturingCommandListener.kt66
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/education/ContextualEducationMetricsLogger.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionKeyTutorialScreen.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt87
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialAnimation.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/OWNERS2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissTransitionInteractor.kt80
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/Media3ActionFactory.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaActions.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/animation/ColorSchemeTransition.kt92
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/plugins/PluginEnablerImpl.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/BuildTextView.kt45
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/dagger/QSModuleBase.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/BaseAutoAddableModule.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/A11yShortcutAutoAddableList.kt49
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddable.kt72
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/AccessibilityTilesInteractor.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ScreenRecordDetailsViewModel.kt34
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/interactor/HearingDevicesTileDataInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModel.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionViewBinder.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/OWNERS12
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTracker.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt56
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractor.kt79
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ImmersiveModeConfirmation.java92
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt71
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarConnectedDisplays.kt (renamed from packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarConntectedDisplays.kt)2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarRootModernization.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/headsup/shared/StatusBarNoHunBehavior.kt61
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt61
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java206
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorLogger.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationIconInteractor.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt56
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt195
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/AppIconProvider.kt42
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/NotificationRowIconViewInflaterFactory.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java130
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationPlaceholderRepository.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt63
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt45
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java82
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImpl.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt46
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/StatusBarOperatorNameViewModel.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/DelayableMarqueeTextView.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/RingerViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt34
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/shared/VolumeDialogLogger.kt46
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderIconProvider.kt40
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModel.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioSharingInteractor.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractor.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/model/SliderType.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModel.kt130
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt92
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/ui/VolumePanelUiEvent.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/GradientColorWallpaper.kt62
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearanceTest.java72
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java40
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepositoryTest.kt50
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt47
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java39
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt50
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java72
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt27
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/LocalBluetoothManagerKosmos.kt8
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/LocalBluetoothProfileManagerKosmos.kt23
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt17
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt7
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/compose/Snapshot.kt10
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissTransitionInteractor.kt (renamed from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DismissKeyguardInteractor.kt)2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt14
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt17
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelKosmos.kt5
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeCarrierConfigRepository.kt9
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioSharingRepository.kt15
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponentKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModelKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModelKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/FakeAudioSharingInteractor.kt13
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractorKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelKosmos.kt39
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/VolumeSlidersViewModelKosmos.kt2
-rw-r--r--packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/BuildScope.kt28
-rw-r--r--packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Events.kt10
-rw-r--r--packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Filter.kt8
-rw-r--r--packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/GroupBy.kt6
-rw-r--r--packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Incremental.kt4
-rw-r--r--packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Merge.kt18
-rw-r--r--packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/State.kt12
-rw-r--r--packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/StateScope.kt60
-rw-r--r--packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Transactional.kt4
-rw-r--r--packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/store/MapK.kt8
-rw-r--r--packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/util/MapPatch.kt2
-rw-r--r--packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/util/Maybe.kt2
-rw-r--r--packages/Vcn/service-b/src/com/android/server/vcn/Vcn.java2
-rw-r--r--packages/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java8
-rw-r--r--packages/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java31
-rw-r--r--packages/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java2
-rwxr-xr-xravenwood/scripts/pta-framework.sh91
-rw-r--r--ravenwood/texts/ravenwood-common-policies.txt7
-rw-r--r--ravenwood/texts/ravenwood-framework-policies.txt73
-rw-r--r--ravenwood/texts/ravenwood-services-policies.txt21
-rwxr-xr-xravenwood/tools/hoststubgen/scripts/dump-jar29
-rw-r--r--ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt53
-rwxr-xr-xravenwood/tools/hoststubgen/test-tiny-framework/diff-and-update-golden.sh9
-rwxr-xr-xravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py20
-rw-r--r--ravenwood/tools/ravenhelper/Android.bp26
-rw-r--r--ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/RavenHelperMain.kt72
-rw-r--r--ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/Annotations.kt66
-rw-r--r--ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/Operations.kt201
-rw-r--r--ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaOptions.kt106
-rw-r--r--ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt479
-rw-r--r--ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/psi/PsiUtil.kt66
-rw-r--r--ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/SourceMapGenerator.kt419
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java112
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java39
-rw-r--r--services/accessibility/java/com/android/server/accessibility/ProxyManager.java4
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java32
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/MagnificationKeyHandler.java133
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java20
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerService.java1966
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java73
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java91
-rw-r--r--services/core/Android.bp2
-rw-r--r--services/core/java/com/android/server/GestureLauncherService.java3
-rw-r--r--services/core/java/com/android/server/OWNERS1
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java18
-rw-r--r--services/core/java/com/android/server/ZramMaintenance.java118
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java4
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java2
-rw-r--r--services/core/java/com/android/server/am/SettingsToPropertiesMapper.java1
-rw-r--r--services/core/java/com/android/server/am/flags.aconfig10
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java2
-rw-r--r--services/core/java/com/android/server/appop/DiscreteOpsDbHelper.java7
-rw-r--r--services/core/java/com/android/server/clipboard/ClipboardService.java33
-rw-r--r--services/core/java/com/android/server/crashrecovery/OWNERS1
-rw-r--r--services/core/java/com/android/server/display/ColorFade.java5
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java67
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java17
-rw-r--r--services/core/java/com/android/server/display/feature/DisplayManagerFlags.java14
-rw-r--r--services/core/java/com/android/server/display/feature/display_flags.aconfig8
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java72
-rw-r--r--services/core/java/com/android/server/hdmi/PowerStatusMonitorActionFromPlayback.java43
-rw-r--r--services/core/java/com/android/server/input/InputGestureManager.java33
-rw-r--r--services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java24
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java31
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java4
-rw-r--r--services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java12
-rw-r--r--services/core/java/com/android/server/location/fudger/LocationFudger.java28
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java5
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java10
-rw-r--r--services/core/java/com/android/server/media/RemoteDisplayProviderProxy.java49
-rw-r--r--services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java8
-rw-r--r--services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java49
-rw-r--r--services/core/java/com/android/server/media/quality/MediaQualityService.java548
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java191
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecordLogger.java15
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java75
-rw-r--r--services/core/java/com/android/server/notification/flags.aconfig7
-rw-r--r--services/core/java/com/android/server/pm/BroadcastHelper.java5
-rw-r--r--services/core/java/com/android/server/pm/DeletePackageHelper.java26
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java5
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java25
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java6
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java23
-rw-r--r--services/core/java/com/android/server/policy/DeviceStateProviderImpl.java60
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java48
-rw-r--r--services/core/java/com/android/server/power/TEST_MAPPING12
-rw-r--r--services/core/java/com/android/server/power/hint/TEST_MAPPING17
-rw-r--r--services/core/java/com/android/server/power/stats/BatteryStatsImpl.java145
-rw-r--r--services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java249
-rw-r--r--services/core/java/com/android/server/power/stats/PowerStatsStore.java35
-rw-r--r--services/core/java/com/android/server/power/stats/UserPowerCalculator.java70
-rw-r--r--services/core/java/com/android/server/security/authenticationpolicy/AuthenticationPolicyService.java13
-rw-r--r--services/core/java/com/android/server/selinux/QuotaExceededException.java23
-rw-r--r--services/core/java/com/android/server/selinux/SelinuxAuditLogsCollector.java147
-rw-r--r--services/core/java/com/android/server/selinux/SelinuxAuditLogsJob.java8
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java23
-rw-r--r--services/core/java/com/android/server/timezonedetector/Environment.java80
-rw-r--r--services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java10
-rw-r--r--services/core/java/com/android/server/timezonedetector/NotifyingTimeZoneChangeListener.java20
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java55
-rw-r--r--services/core/java/com/android/server/vibrator/VibratorManagerService.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java202
-rw-r--r--services/core/java/com/android/server/wm/ActivitySnapshotController.java16
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java1
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java6
-rw-r--r--services/core/java/com/android/server/wm/AppCompatAspectRatioPolicy.java11
-rw-r--r--services/core/java/com/android/server/wm/AppCompatController.java44
-rw-r--r--services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java2
-rw-r--r--services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java2
-rw-r--r--services/core/java/com/android/server/wm/AppCompatOverrides.java18
-rw-r--r--services/core/java/com/android/server/wm/AppCompatReachabilityPolicy.java4
-rw-r--r--services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java125
-rw-r--r--services/core/java/com/android/server/wm/AppCompatUtils.java6
-rw-r--r--services/core/java/com/android/server/wm/BackNavigationController.java24
-rw-r--r--services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java6
-rw-r--r--services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java6
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java20
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java66
-rw-r--r--services/core/java/com/android/server/wm/DragDropController.java4
-rw-r--r--services/core/java/com/android/server/wm/DragState.java39
-rw-r--r--services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java5
-rw-r--r--services/core/java/com/android/server/wm/EventLogTags.logtags2
-rw-r--r--services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java533
-rw-r--r--services/core/java/com/android/server/wm/LaunchParamsController.java3
-rw-r--r--services/core/java/com/android/server/wm/LockTaskController.java2
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java8
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java32
-rw-r--r--services/core/java/com/android/server/wm/SnapshotPersistQueue.java7
-rw-r--r--services/core/java/com/android/server/wm/StrictModeFlash.java5
-rw-r--r--services/core/java/com/android/server/wm/Task.java18
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java24
-rw-r--r--services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java6
-rw-r--r--services/core/java/com/android/server/wm/TaskPersister.java6
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java13
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotPersister.java15
-rw-r--r--services/core/java/com/android/server/wm/Transition.java7
-rw-r--r--services/core/java/com/android/server/wm/TransparentPolicy.java2
-rw-r--r--services/core/java/com/android/server/wm/Watermark.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerFlags.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java92
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java18
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java83
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java66
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfacePlacer.java1
-rw-r--r--services/core/xsd/device-state-config/device-state-config.xsd9
-rw-r--r--services/core/xsd/device-state-config/schema/current.txt7
-rw-r--r--services/credentials/java/com/android/server/credentials/RequestSession.java72
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java2
-rw-r--r--services/foldables/devicestateprovider/src/com/android/server/policy/BookStyleClosedStatePredicate.java56
-rw-r--r--services/foldables/devicestateprovider/src/com/android/server/policy/BookStyleDeviceStatePolicy.java17
-rw-r--r--services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java41
-rw-r--r--services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig10
-rw-r--r--services/foldables/devicestateprovider/tests/src/com/android/server/policy/BookStyleDeviceStatePolicyTest.java76
-rw-r--r--services/incremental/IncrementalService.cpp2
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java6
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/UserDataRepositoryTest.java10
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java48
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java22
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/fudger/LocationFudgerTest.java27
-rw-r--r--services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java53
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryChargeCalculatorTest.java5
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java29
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java6
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java62
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java34
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java17
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java30
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/UserPowerCalculatorTest.java165
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerStatsCollectorTest.java1
-rw-r--r--services/tests/selinux/src/com/android/server/selinux/SelinuxAuditLogsCollectorTest.java38
-rw-r--r--services/tests/selinux/src/com/android/server/selinux/SelinuxAuditLogsJobTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java81
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java90
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java66
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java17
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationKeyHandlerTest.java256
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java30
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java24
-rw-r--r--services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java40
-rw-r--r--services/tests/servicestests/src/com/android/server/security/authenticationpolicy/AuthenticationPolicyServiceTest.java57
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/FakeEnvironment.java141
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/NotifyingTimeZoneChangeListenerTest.java114
-rw-r--r--services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java110
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java120
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java127
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java118
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java2
-rw-r--r--services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java5
-rw-r--r--services/tests/wmtests/Android.bp66
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java16
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppCompatAspectRatioOverridesTest.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppCompatFocusOverridesTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationOverridesTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationPolicyTest.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppCompatUtilsTest.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DesktopAppCompatAspectRatioPolicyTests.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java50
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java36
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java38
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java24
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java38
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java169
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java40
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java48
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TransparentPolicyTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTestSupport.kt112
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java3
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java7
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java62
-rw-r--r--tests/CompanionDeviceMultiDeviceTests/client/Android.bp1
-rw-r--r--tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt19
-rw-r--r--tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt72
-rw-r--r--tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml2
-rw-r--r--tests/NetworkSecurityConfigTest/res/xml/nested_domains.xml2
-rw-r--r--tests/NetworkSecurityConfigTest/res/xml/pins1.xml2
-rw-r--r--tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java4
-rw-r--r--tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java2
-rw-r--r--tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java5
-rw-r--r--tools/aapt2/dump/DumpManifest.cpp2
1165 files changed, 22397 insertions, 12389 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index a60ced5835ea..f249884cb1a0 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -107,7 +107,7 @@ aconfig_declarations_group {
"com.android.server.flags.services-aconfig-java",
"com.android.text.flags-aconfig-java",
"com.android.window.flags.window-aconfig-java",
- "configinfra_framework_flags_java_lib",
+ "configinfra_framework_flags_java_exported_lib",
"conscrypt_exported_aconfig_flags_lib",
"device_policy_aconfig_flags_lib",
"display_flags_lib",
@@ -467,7 +467,7 @@ java_aconfig_library {
"//apex_available:platform",
"com.android.art",
"com.android.art.debug",
- "com.android.btservices",
+ "com.android.bt",
"com.android.mediaprovider",
"com.android.permission",
],
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 60ba3b896a28..829442aed6ac 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -96,6 +96,7 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserPackage;
+import android.content.res.Resources;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.BatteryStatsInternal;
@@ -1784,7 +1785,8 @@ public class AlarmManagerService extends SystemService {
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
mStartUserBeforeScheduledAlarms = Flags.startUserBeforeScheduledAlarms()
- && UserManager.supportsMultipleUsers();
+ && UserManager.supportsMultipleUsers() && Resources.getSystem().getBoolean(
+ com.android.internal.R.bool.config_allowAlarmsOnStoppedUsers);
if (mStartUserBeforeScheduledAlarms) {
mUserWakeupStore = new UserWakeupStore();
mUserWakeupStore.init();
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index a949ff5a331b..787fdee6ee16 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -1023,7 +1023,6 @@ stubs_defaults {
api_levels_annotations_enabled: true,
api_levels_annotations_dirs: [
"sdk-dir",
- "api-versions-jars-dir",
],
}
diff --git a/api/api.go b/api/api.go
index cbdb7e81ab86..640773be0f9b 100644
--- a/api/api.go
+++ b/api/api.go
@@ -104,8 +104,9 @@ func (a *CombinedApis) DepsMutator(ctx android.BottomUpMutatorContext) {
}
func (a *CombinedApis) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- ctx.WalkDeps(func(child, parent android.Module) bool {
- if _, ok := android.OtherModuleProvider(ctx, child, java.AndroidLibraryInfoProvider); ok && child.Name() != "framework-res" {
+ ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool {
+ javaInfo, ok := android.OtherModuleProvider(ctx, child, java.JavaInfoProvider)
+ if ok && javaInfo.AndroidLibraryDependencyInfo != nil && child.Name() != "framework-res" {
// Stubs of BCP and SSCP libraries should not have any dependencies on apps
// This check ensures that we do not run into circular dependencies when UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT=true
ctx.ModuleErrorf(
diff --git a/cmds/am/am.sh b/cmds/am/am.sh
index 54c2d394be2c..76ec214cb446 100755
--- a/cmds/am/am.sh
+++ b/cmds/am/am.sh
@@ -1,5 +1,8 @@
#!/system/bin/sh
+# set to top-app process group
+settaskprofile $$ SCHED_SP_TOP_APP >/dev/null 2>&1 || true
+
if [ "$1" != "instrument" ] ; then
cmd activity "$@"
else
diff --git a/cmds/uinput/README.md b/cmds/uinput/README.md
index 6138388b30c7..5734c847be87 100644
--- a/cmds/uinput/README.md
+++ b/cmds/uinput/README.md
@@ -59,7 +59,7 @@ Register a new uinput device
| `name` | string | Device name |
| `vid` | 16-bit integer | Vendor ID |
| `pid` | 16-bit integer | Product ID |
-| `bus` | string | Bus that device should use |
+| `bus` | string | The bus to report |
| `port` | string | `phys` value to report |
| `configuration` | object array | uinput device configuration|
| `ff_effects_max` | integer | `ff_effects_max` value |
@@ -68,8 +68,11 @@ Register a new uinput device
`id` is used for matching the subsequent commands to a specific device to avoid ambiguity when
multiple devices are registered.
-`bus` is used to determine how the uinput device is connected to the host. The options are `"usb"`
-and `"bluetooth"`.
+`bus` specifies the bus that the kernel should report the device as being connected to. The most
+common values are `"usb"` and `"bluetooth"`, but any bus with a `BUS_…` constant in the [Linux
+kernel's input.h][input.h] can be specified using the part of its identifier after `BUS_`. For
+example, to specify the SPI bus type (`BUS_SPI` in the kernel header), use `"spi"` (or `"SPI"`,
+since it's case-insensitive).
Device configuration is used to configure the uinput device. The `type` field provides a `UI_SET_*`
control code as an integer value or a string label (e.g. `"UI_SET_EVBIT"`), and data is a vector of
@@ -137,6 +140,7 @@ Example:
}
```
+[input.h]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/third_party/kernel/upstream/include/uapi/linux/input.h?q=BUS_
[struct input_absinfo]: https://cs.android.com/android/platform/superproject/main/+/main:bionic/libc/kernel/uapi/linux/input.h?q=%22struct%20input_absinfo%22
##### Waiting for registration
diff --git a/core/api/current.txt b/core/api/current.txt
index b7f7a7f9e779..26c64bd7adbc 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -10249,23 +10249,23 @@ package android.companion.virtual {
public final class VirtualDevice implements android.os.Parcelable {
method public int describeContents();
method public int getDeviceId();
- method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") @NonNull public int[] getDisplayIds();
- method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") @Nullable public CharSequence getDisplayName();
+ method @NonNull public int[] getDisplayIds();
+ method @Nullable public CharSequence getDisplayName();
method @Nullable public String getName();
- method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") @Nullable public String getPersistentDeviceId();
- method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") public boolean hasCustomSensorSupport();
+ method @Nullable public String getPersistentDeviceId();
+ method public boolean hasCustomSensorSupport();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.VirtualDevice> CREATOR;
}
public final class VirtualDeviceManager {
- method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") @Nullable public android.companion.virtual.VirtualDevice getVirtualDevice(int);
+ method @Nullable public android.companion.virtual.VirtualDevice getVirtualDevice(int);
method @NonNull public java.util.List<android.companion.virtual.VirtualDevice> getVirtualDevices();
- method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") public void registerVirtualDeviceListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.VirtualDeviceListener);
- method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") public void unregisterVirtualDeviceListener(@NonNull android.companion.virtual.VirtualDeviceManager.VirtualDeviceListener);
+ method public void registerVirtualDeviceListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.VirtualDeviceListener);
+ method public void unregisterVirtualDeviceListener(@NonNull android.companion.virtual.VirtualDeviceManager.VirtualDeviceListener);
}
- @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") public static interface VirtualDeviceManager.VirtualDeviceListener {
+ public static interface VirtualDeviceManager.VirtualDeviceListener {
method public default void onVirtualDeviceClosed(int);
method public default void onVirtualDeviceCreated(int);
}
@@ -38278,7 +38278,6 @@ package android.provider {
field public static final String ACTION_NOTIFICATION_LISTENER_DETAIL_SETTINGS = "android.settings.NOTIFICATION_LISTENER_DETAIL_SETTINGS";
field public static final String ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
field public static final String ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_SETTINGS";
- field @FlaggedApi("android.provider.system_regional_preferences_api_enabled") public static final String ACTION_NUMBERING_SYSTEM_SETTINGS = "android.settings.NUMBERING_SYSTEM_SETTINGS";
field public static final String ACTION_PRINT_SETTINGS = "android.settings.ACTION_PRINT_SETTINGS";
field public static final String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
field public static final String ACTION_PROCESS_WIFI_EASY_CONNECT_URI = "android.settings.PROCESS_WIFI_EASY_CONNECT_URI";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 16c70174d5c2..6e0defed1e27 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1290,9 +1290,7 @@ package android.app {
public class WallpaperManager {
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public void clearWallpaper(int, int);
- method @FlaggedApi("android.app.customization_packs_apis") public static int getOrientation(@NonNull android.graphics.Point);
method @FloatRange(from=0.0f, to=1.0f) @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT) public float getWallpaperDimAmount();
- method @FlaggedApi("android.app.customization_packs_apis") @Nullable public android.os.ParcelFileDescriptor getWallpaperFile(int, boolean);
method @FlaggedApi("android.app.live_wallpaper_content_handling") @Nullable @RequiresPermission(android.Manifest.permission.READ_WALLPAPER_INTERNAL) public android.app.wallpaper.WallpaperInstance getWallpaperInstance(int);
method public void setDisplayOffset(android.os.IBinder, int, int);
method @FlaggedApi("com.android.window.flags.multi_crop") @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setStreamWithCrops(@NonNull java.io.InputStream, @NonNull android.util.SparseArray<android.graphics.Rect>, boolean, int) throws java.io.IOException;
@@ -1301,10 +1299,6 @@ package android.app {
method @FlaggedApi("android.app.live_wallpaper_content_handling") @RequiresPermission(allOf={android.Manifest.permission.SET_WALLPAPER_COMPONENT, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}, conditional=true) public boolean setWallpaperComponentWithDescription(@NonNull android.app.wallpaper.WallpaperDescription, int);
method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT) public boolean setWallpaperComponentWithFlags(@NonNull android.content.ComponentName, int);
method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT) public void setWallpaperDimAmount(@FloatRange(from=0.0f, to=1.0f) float);
- field @FlaggedApi("android.app.customization_packs_apis") public static final int ORIENTATION_LANDSCAPE = 1; // 0x1
- field @FlaggedApi("android.app.customization_packs_apis") public static final int ORIENTATION_PORTRAIT = 0; // 0x0
- field @FlaggedApi("android.app.customization_packs_apis") public static final int ORIENTATION_SQUARE_LANDSCAPE = 3; // 0x3
- field @FlaggedApi("android.app.customization_packs_apis") public static final int ORIENTATION_SQUARE_PORTRAIT = 2; // 0x2
}
}
@@ -3171,6 +3165,11 @@ package android.app.wallpaper {
method @NonNull public android.util.SparseArray<android.graphics.Rect> getCropHints();
}
+ public static final class WallpaperDescription.Builder {
+ method @NonNull public android.app.wallpaper.WallpaperDescription.Builder setCropHints(@NonNull java.util.Map<android.graphics.Point,android.graphics.Rect>);
+ method @NonNull public android.app.wallpaper.WallpaperDescription.Builder setCropHints(@NonNull android.util.SparseArray<android.graphics.Rect>);
+ }
+
}
package android.app.wallpapereffectsgeneration {
@@ -3399,18 +3398,18 @@ package android.companion.virtual {
}
public final class VirtualDevice implements android.os.Parcelable {
- method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") public boolean hasCustomAudioInputSupport();
- method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") public boolean hasCustomCameraSupport();
+ method public boolean hasCustomAudioInputSupport();
+ method public boolean hasCustomCameraSupport();
}
public final class VirtualDeviceManager {
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.VirtualDeviceManager.VirtualDevice createVirtualDevice(int, @NonNull android.companion.virtual.VirtualDeviceParams);
- method @FlaggedApi("android.companion.virtual.flags.persistent_device_id_api") @NonNull public java.util.Set<java.lang.String> getAllPersistentDeviceIds();
- method @FlaggedApi("android.companion.virtual.flags.persistent_device_id_api") @Nullable public CharSequence getDisplayNameForPersistentDeviceId(@NonNull String);
+ method @NonNull public java.util.Set<java.lang.String> getAllPersistentDeviceIds();
+ method @Nullable public CharSequence getDisplayNameForPersistentDeviceId(@NonNull String);
field public static final int LAUNCH_FAILURE_NO_ACTIVITY = 2; // 0x2
field public static final int LAUNCH_FAILURE_PENDING_INTENT_CANCELED = 1; // 0x1
field public static final int LAUNCH_SUCCESS = 0; // 0x0
- field @FlaggedApi("android.companion.virtual.flags.persistent_device_id_api") public static final String PERSISTENT_DEVICE_ID_DEFAULT = "default:0";
+ field public static final String PERSISTENT_DEVICE_ID_DEFAULT = "default:0";
}
public static interface VirtualDeviceManager.ActivityListener {
@@ -3432,7 +3431,7 @@ package android.companion.virtual {
public static class VirtualDeviceManager.VirtualDevice implements java.lang.AutoCloseable {
method public void addActivityListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
- method @FlaggedApi("android.companion.virtual.flags.dynamic_policy") public void addActivityPolicyExemption(@NonNull android.content.ComponentName);
+ method public void addActivityPolicyExemption(@NonNull android.content.ComponentName);
method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public void addActivityPolicyExemption(@NonNull android.companion.virtual.ActivityPolicyExemption);
method public void addSoundEffectListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.SoundEffectListener);
method public void close();
@@ -3448,20 +3447,20 @@ package android.companion.virtual {
method @Deprecated @NonNull public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
method @NonNull public android.hardware.input.VirtualNavigationTouchpad createVirtualNavigationTouchpad(@NonNull android.hardware.input.VirtualNavigationTouchpadConfig);
method @FlaggedApi("android.companion.virtualdevice.flags.virtual_rotary") @NonNull public android.hardware.input.VirtualRotaryEncoder createVirtualRotaryEncoder(@NonNull android.hardware.input.VirtualRotaryEncoderConfig);
- method @FlaggedApi("android.companion.virtual.flags.virtual_stylus") @NonNull public android.hardware.input.VirtualStylus createVirtualStylus(@NonNull android.hardware.input.VirtualStylusConfig);
+ method @NonNull public android.hardware.input.VirtualStylus createVirtualStylus(@NonNull android.hardware.input.VirtualStylusConfig);
method @NonNull public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.input.VirtualTouchscreenConfig);
method @Deprecated @NonNull public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
method public int getDeviceId();
- method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") @Nullable public String getPersistentDeviceId();
+ method @Nullable public String getPersistentDeviceId();
method @NonNull public java.util.List<android.companion.virtual.sensor.VirtualSensor> getVirtualSensorList();
method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") public void goToSleep();
method public void launchPendingIntent(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
method public void registerIntentInterceptor(@NonNull android.content.IntentFilter, @NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.IntentInterceptorCallback);
method public void removeActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
- method @FlaggedApi("android.companion.virtual.flags.dynamic_policy") public void removeActivityPolicyExemption(@NonNull android.content.ComponentName);
+ method public void removeActivityPolicyExemption(@NonNull android.content.ComponentName);
method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public void removeActivityPolicyExemption(@NonNull android.companion.virtual.ActivityPolicyExemption);
method public void removeSoundEffectListener(@NonNull android.companion.virtual.VirtualDeviceManager.SoundEffectListener);
- method @FlaggedApi("android.companion.virtual.flags.dynamic_policy") public void setDevicePolicy(int, int);
+ method public void setDevicePolicy(int, int);
method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public void setDevicePolicy(int, int, int);
method @FlaggedApi("android.companion.virtual.flags.vdm_custom_ime") public void setDisplayImePolicy(int, int);
method public void setShowPointerIcon(boolean);
@@ -3481,7 +3480,7 @@ package android.companion.virtual {
method @Deprecated public int getDefaultNavigationPolicy();
method public int getDevicePolicy(int);
method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @NonNull public java.time.Duration getDimDuration();
- method @FlaggedApi("android.companion.virtual.flags.vdm_custom_home") @Nullable public android.content.ComponentName getHomeComponent();
+ method @Nullable public android.content.ComponentName getHomeComponent();
method @FlaggedApi("android.companion.virtual.flags.vdm_custom_ime") @Nullable public android.content.ComponentName getInputMethodComponent();
method public int getLockState();
method @Nullable public String getName();
@@ -3498,11 +3497,11 @@ package android.companion.virtual {
field public static final int LOCK_STATE_DEFAULT = 0; // 0x0
field @Deprecated public static final int NAVIGATION_POLICY_DEFAULT_ALLOWED = 0; // 0x0
field @Deprecated public static final int NAVIGATION_POLICY_DEFAULT_BLOCKED = 1; // 0x1
- field @FlaggedApi("android.companion.virtual.flags.dynamic_policy") public static final int POLICY_TYPE_ACTIVITY = 3; // 0x3
+ field public static final int POLICY_TYPE_ACTIVITY = 3; // 0x3
field public static final int POLICY_TYPE_AUDIO = 1; // 0x1
field @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public static final int POLICY_TYPE_BLOCKED_ACTIVITY = 6; // 0x6
field @FlaggedApi("android.companion.virtual.flags.virtual_camera") public static final int POLICY_TYPE_CAMERA = 5; // 0x5
- field @FlaggedApi("android.companion.virtual.flags.cross_device_clipboard") public static final int POLICY_TYPE_CLIPBOARD = 4; // 0x4
+ field public static final int POLICY_TYPE_CLIPBOARD = 4; // 0x4
field @FlaggedApi("android.companion.virtualdevice.flags.default_device_camera_access_policy") public static final int POLICY_TYPE_DEFAULT_DEVICE_CAMERA_ACCESS = 7; // 0x7
field public static final int POLICY_TYPE_RECENTS = 2; // 0x2
field public static final int POLICY_TYPE_SENSORS = 0; // 0x0
@@ -3520,7 +3519,7 @@ package android.companion.virtual {
method @Deprecated @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedCrossTaskNavigations(@NonNull java.util.Set<android.content.ComponentName>);
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setDevicePolicy(int, int);
method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setDimDuration(@NonNull java.time.Duration);
- method @FlaggedApi("android.companion.virtual.flags.vdm_custom_home") @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setHomeComponent(@Nullable android.content.ComponentName);
+ method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setHomeComponent(@Nullable android.content.ComponentName);
method @FlaggedApi("android.companion.virtual.flags.vdm_custom_ime") @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setInputMethodComponent(@Nullable android.content.ComponentName);
method @NonNull @RequiresPermission(value=android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY, conditional=true) public android.companion.virtual.VirtualDeviceParams.Builder setLockState(int);
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setName(@NonNull String);
@@ -5325,20 +5324,20 @@ package android.hardware.display {
method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfigurationForDisplay(@NonNull android.hardware.display.BrightnessConfiguration, @NonNull String);
method @Deprecated @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_SATURATION) public void setSaturationLevel(float);
- field @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") public static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 128; // 0x80
+ field public static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 128; // 0x80
field public static final int VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED = 65536; // 0x10000
field public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1024; // 0x400
}
public final class VirtualDisplayConfig implements android.os.Parcelable {
method @FlaggedApi("android.companion.virtualdevice.flags.virtual_display_insets") @Nullable public android.view.DisplayCutout getDisplayCutout();
- method @FlaggedApi("android.companion.virtual.flags.vdm_custom_home") public boolean isHomeSupported();
+ method public boolean isHomeSupported();
method @FlaggedApi("com.android.window.flags.vdm_force_app_universal_resizable_api") public boolean isIgnoreActivitySizeRestrictions();
}
public static final class VirtualDisplayConfig.Builder {
method @FlaggedApi("android.companion.virtualdevice.flags.virtual_display_insets") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setDisplayCutout(@Nullable android.view.DisplayCutout);
- method @FlaggedApi("android.companion.virtual.flags.vdm_custom_home") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setHomeSupported(boolean);
+ method @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setHomeSupported(boolean);
method @FlaggedApi("com.android.window.flags.vdm_force_app_universal_resizable_api") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setIgnoreActivitySizeRestrictions(boolean);
}
@@ -5970,13 +5969,13 @@ package android.hardware.input {
method @NonNull public android.hardware.input.VirtualRotaryEncoderScrollEvent.Builder setScrollAmount(@FloatRange(from=-1.0F, to=1.0f) float);
}
- @FlaggedApi("android.companion.virtual.flags.virtual_stylus") public class VirtualStylus implements java.io.Closeable {
+ public class VirtualStylus implements java.io.Closeable {
method public void close();
method public void sendButtonEvent(@NonNull android.hardware.input.VirtualStylusButtonEvent);
method public void sendMotionEvent(@NonNull android.hardware.input.VirtualStylusMotionEvent);
}
- @FlaggedApi("android.companion.virtual.flags.virtual_stylus") public final class VirtualStylusButtonEvent implements android.os.Parcelable {
+ public final class VirtualStylusButtonEvent implements android.os.Parcelable {
method public int describeContents();
method public int getAction();
method public int getButtonCode();
@@ -5989,7 +5988,7 @@ package android.hardware.input {
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.input.VirtualStylusButtonEvent> CREATOR;
}
- @FlaggedApi("android.companion.virtual.flags.virtual_stylus") public static final class VirtualStylusButtonEvent.Builder {
+ public static final class VirtualStylusButtonEvent.Builder {
ctor public VirtualStylusButtonEvent.Builder();
method @NonNull public android.hardware.input.VirtualStylusButtonEvent build();
method @NonNull public android.hardware.input.VirtualStylusButtonEvent.Builder setAction(int);
@@ -5997,7 +5996,7 @@ package android.hardware.input {
method @NonNull public android.hardware.input.VirtualStylusButtonEvent.Builder setEventTimeNanos(long);
}
- @FlaggedApi("android.companion.virtual.flags.virtual_stylus") public final class VirtualStylusConfig extends android.hardware.input.VirtualInputDeviceConfig implements android.os.Parcelable {
+ public final class VirtualStylusConfig extends android.hardware.input.VirtualInputDeviceConfig implements android.os.Parcelable {
method public int describeContents();
method public int getHeight();
method public int getWidth();
@@ -6005,12 +6004,12 @@ package android.hardware.input {
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.input.VirtualStylusConfig> CREATOR;
}
- @FlaggedApi("android.companion.virtual.flags.virtual_stylus") public static final class VirtualStylusConfig.Builder extends android.hardware.input.VirtualInputDeviceConfig.Builder<android.hardware.input.VirtualStylusConfig.Builder> {
+ public static final class VirtualStylusConfig.Builder extends android.hardware.input.VirtualInputDeviceConfig.Builder<android.hardware.input.VirtualStylusConfig.Builder> {
ctor public VirtualStylusConfig.Builder(@IntRange(from=1) int, @IntRange(from=1) int);
method @NonNull public android.hardware.input.VirtualStylusConfig build();
}
- @FlaggedApi("android.companion.virtual.flags.virtual_stylus") public final class VirtualStylusMotionEvent implements android.os.Parcelable {
+ public final class VirtualStylusMotionEvent implements android.os.Parcelable {
method public int describeContents();
method public int getAction();
method public long getEventTimeNanos();
@@ -6029,7 +6028,7 @@ package android.hardware.input {
field public static final int TOOL_TYPE_STYLUS = 2; // 0x2
}
- @FlaggedApi("android.companion.virtual.flags.virtual_stylus") public static final class VirtualStylusMotionEvent.Builder {
+ public static final class VirtualStylusMotionEvent.Builder {
ctor public VirtualStylusMotionEvent.Builder();
method @NonNull public android.hardware.input.VirtualStylusMotionEvent build();
method @NonNull public android.hardware.input.VirtualStylusMotionEvent.Builder setAction(int);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index a352d9d2ea06..0126db70296c 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -436,34 +436,6 @@ package android.app {
ctor public PictureInPictureUiState(boolean);
}
- public class PropertyInvalidatedCache<Query, Result> {
- ctor public PropertyInvalidatedCache(int, @NonNull String, @NonNull String, @NonNull String, @NonNull android.app.PropertyInvalidatedCache.QueryHandler<Query,Result>);
- method @NonNull public static String createPropertyName(@NonNull String, @NonNull String);
- method public void disableForCurrentProcess();
- method public static void disableForCurrentProcess(@NonNull String);
- method public static void disableForTestMode();
- method public final void disableInstance();
- method public final void disableSystemWide();
- method public final void forgetDisableLocal();
- method public boolean getDisabledState();
- method public void invalidateCache();
- method public static void invalidateCache(@NonNull String, @NonNull String);
- method public final boolean isDisabled();
- method @Nullable public Result query(@NonNull Query);
- method public static void setTestMode(boolean);
- method public void testPropertyName();
- field public static final String MODULE_BLUETOOTH = "bluetooth";
- field public static final String MODULE_SYSTEM = "system_server";
- field public static final String MODULE_TELEPHONY = "telephony";
- field public static final String MODULE_TEST = "test";
- }
-
- public abstract static class PropertyInvalidatedCache.QueryHandler<Q, R> {
- ctor public PropertyInvalidatedCache.QueryHandler();
- method @Nullable public abstract R apply(@NonNull Q);
- method public boolean shouldBypassCache(@NonNull Q);
- }
-
public class StatusBarManager {
method public void cancelRequestAddTile(@NonNull String);
method public void clickNotification(@Nullable String, int, int, boolean);
@@ -536,7 +508,6 @@ package android.app {
method @Nullable public android.graphics.Bitmap getBitmap();
method @Nullable public android.graphics.Bitmap getBitmapAsUser(int, boolean, int);
method @FlaggedApi("com.android.window.flags.multi_crop") @NonNull @RequiresPermission(android.Manifest.permission.READ_WALLPAPER_INTERNAL) public java.util.List<android.graphics.Rect> getBitmapCrops(@NonNull java.util.List<android.graphics.Point>, int, boolean);
- method @FlaggedApi("android.app.customization_packs_apis") @NonNull @RequiresPermission(android.Manifest.permission.READ_WALLPAPER_INTERNAL) public android.util.SparseArray<android.graphics.Rect> getBitmapCrops(int);
method @FlaggedApi("com.android.window.flags.multi_crop") @NonNull public java.util.List<android.graphics.Rect> getBitmapCrops(@NonNull android.graphics.Point, @NonNull java.util.List<android.graphics.Point>, @Nullable java.util.Map<android.graphics.Point,android.graphics.Rect>);
method public boolean isLockscreenLiveWallpaperEnabled();
method @Nullable public android.graphics.Rect peekBitmapDimensions();
@@ -910,15 +881,6 @@ package android.app.usage {
}
-package android.app.wallpaper {
-
- public static final class WallpaperDescription.Builder {
- method @NonNull public android.app.wallpaper.WallpaperDescription.Builder setCropHints(@NonNull java.util.Map<android.graphics.Point,android.graphics.Rect>);
- method @NonNull public android.app.wallpaper.WallpaperDescription.Builder setCropHints(@NonNull android.util.SparseArray<android.graphics.Rect>);
- }
-
-}
-
package android.appwidget {
public class AppWidgetManager {
@@ -2444,17 +2406,28 @@ package android.os {
method @FlaggedApi("android.os.mainline_vcn_platform_api") public final void removeEqualMessages(int, @Nullable Object);
}
- public class IpcDataCache<Query, Result> extends android.app.PropertyInvalidatedCache<Query,Result> {
+ public class IpcDataCache<Query, Result> {
ctor public IpcDataCache(int, @NonNull String, @NonNull String, @NonNull String, @NonNull android.os.IpcDataCache.QueryHandler<Query,Result>);
+ method public void disableForCurrentProcess();
method public static void disableForCurrentProcess(@NonNull String);
+ method public final void disableInstance();
+ method public final void disableSystemWide();
+ method public final void forgetDisableLocal();
+ method public boolean getDisabledState();
+ method public void invalidateCache();
method public static void invalidateCache(@NonNull String, @NonNull String);
+ method public final boolean isDisabled();
+ method @Nullable public Result query(@NonNull Query);
+ method public static void setTestMode(boolean);
field public static final String MODULE_BLUETOOTH = "bluetooth";
field public static final String MODULE_SYSTEM = "system_server";
field public static final String MODULE_TEST = "test";
}
- public abstract static class IpcDataCache.QueryHandler<Q, R> extends android.app.PropertyInvalidatedCache.QueryHandler<Q,R> {
+ public abstract static class IpcDataCache.QueryHandler<Q, R> {
ctor public IpcDataCache.QueryHandler();
+ method @Nullable public abstract R apply(@NonNull Q);
+ method public boolean shouldBypassCache(@NonNull Q);
}
public final class MessageQueue {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 4782205e3b21..220fbb5c16a6 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -26,8 +26,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.inMultiWindowMode;
import static android.os.Process.myUid;
-import static com.android.sdksandbox.flags.Flags.sandboxActivitySdkBasedContext;
-
import static java.lang.Character.MIN_VALUE;
import android.Manifest;
@@ -8999,12 +8997,11 @@ public class Activity extends ContextThemeWrapper
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
IBinder shareableActivityToken, IBinder initialCallerInfoAccessToken) {
- if (sandboxActivitySdkBasedContext()) {
- // Sandbox activities extract a token from the intent's extra to identify the related
- // SDK as part of overriding attachBaseContext, then it wraps the passed context in an
- // SDK ContextWrapper, so mIntent has to be set before calling attachBaseContext.
- mIntent = intent;
- }
+
+ // mIntent field hast to be set before calling attachBaseContext, as SDK Runtime activities
+ // extract a token from the intent's extra to identify the related SDK as part of overriding
+ // attachBaseContext.
+ mIntent = intent;
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
@@ -9030,8 +9027,6 @@ public class Activity extends ContextThemeWrapper
mShareableActivityToken = shareableActivityToken;
mIdent = ident;
mApplication = application;
- //TODO(b/300059435): do not set the mIntent again as part of the flag clean up.
- mIntent = intent;
mReferrer = referrer;
mComponent = intent.getComponent();
mTitle = title;
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index af6978a6b70c..82c746a8ad4c 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -1846,6 +1846,7 @@ public class ActivityOptions extends ComponentOptions {
}
/** @hide */
+ @WindowConfiguration.WindowingMode
public int getLaunchWindowingMode() {
return mLaunchWindowingMode;
}
@@ -1855,7 +1856,7 @@ public class ActivityOptions extends ComponentOptions {
* @hide
*/
@TestApi
- public void setLaunchWindowingMode(int windowingMode) {
+ public void setLaunchWindowingMode(@WindowConfiguration.WindowingMode int windowingMode) {
mLaunchWindowingMode = windowingMode;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 717a2acb4b4a..2cfba4b8468f 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -41,7 +41,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 android.annotation.NonNull;
import android.annotation.Nullable;
@@ -4072,9 +4071,7 @@ public final class ActivityThread extends ClientTransactionHandler
r.activityInfo.targetActivity);
}
- boolean isSandboxActivityContext =
- sandboxActivitySdkBasedContext()
- && SdkSandboxActivityAuthority.isSdkSandboxActivityIntent(
+ boolean isSandboxActivityContext = SdkSandboxActivityAuthority.isSdkSandboxActivityIntent(
mSystemContext, r.intent);
boolean isSandboxedSdkContextUsed = false;
ContextImpl activityBaseContext;
@@ -4734,6 +4731,7 @@ public final class ActivityThread extends ClientTransactionHandler
}
private void reportSplashscreenViewShown(IBinder token, SplashScreenView view) {
+ Trace.instant(Trace.TRACE_TAG_VIEW, "reportSplashscreenViewShown");
ActivityClient.getInstance().reportSplashScreenAttached(token);
synchronized (this) {
if (mSplashScreenGlobal != null) {
@@ -4751,10 +4749,32 @@ public final class ActivityThread extends ClientTransactionHandler
final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
transaction.hide(startingWindowLeash);
- decorView.getViewRootImpl().applyTransactionOnDraw(transaction);
view.syncTransferSurfaceOnDraw();
- // Tell server we can remove the starting window
- decorView.postOnAnimation(() -> reportSplashscreenViewShown(token, view));
+
+ if (com.android.window.flags.Flags.useRtFrameCallbackForSplashScreenTransfer()
+ && decorView.isHardwareAccelerated()) {
+ decorView.getViewRootImpl().registerRtFrameCallback(
+ new HardwareRenderer.FrameDrawingCallback() {
+ @Override
+ public void onFrameDraw(long frame) { }
+ @Override
+ public HardwareRenderer.FrameCommitCallback onFrameDraw(
+ int syncResult, long frame) {
+ return didProduceBuffer -> {
+ Trace.instant(Trace.TRACE_TAG_VIEW, "transferSplashscreenView");
+ transaction.apply();
+ // Tell server we can remove the starting window after frame commit.
+ decorView.postOnAnimation(() ->
+ reportSplashscreenViewShown(token, view));
+ };
+ }
+ });
+ } else {
+ Trace.instant(Trace.TRACE_TAG_VIEW, "transferSplashscreenView_software");
+ decorView.getViewRootImpl().applyTransactionOnDraw(transaction);
+ // Tell server we can remove the starting window after frame commit.
+ decorView.postOnAnimation(() -> reportSplashscreenViewShown(token, view));
+ }
}
/**
diff --git a/core/java/android/app/ApplicationStartInfo.java b/core/java/android/app/ApplicationStartInfo.java
index f34341fd14e1..3214bd8f01fc 100644
--- a/core/java/android/app/ApplicationStartInfo.java
+++ b/core/java/android/app/ApplicationStartInfo.java
@@ -729,6 +729,7 @@ public final class ApplicationStartInfo implements Parcelable {
return 0;
}
+ // LINT.IfChange(write_parcel)
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mStartupState);
@@ -753,6 +754,7 @@ public final class ApplicationStartInfo implements Parcelable {
dest.writeLong(mMonoticCreationTimeMs);
dest.writeInt(mStartComponent);
}
+ // LINT.ThenChange(:read_parcel)
/** @hide */
public ApplicationStartInfo(long monotonicCreationTimeMs) {
@@ -779,6 +781,7 @@ public final class ApplicationStartInfo implements Parcelable {
}
/** @hide */
+ // LINT.IfChange(read_parcel)
@VisibleForTesting
public ApplicationStartInfo(@NonNull Parcel in) {
mStartupState = in.readInt();
@@ -803,6 +806,7 @@ public final class ApplicationStartInfo implements Parcelable {
mMonoticCreationTimeMs = in.readLong();
mStartComponent = in.readInt();
}
+ // LINT.ThenChange(:write_parcel)
private static String intern(@Nullable String source) {
return source != null ? source.intern() : null;
@@ -835,6 +839,7 @@ public final class ApplicationStartInfo implements Parcelable {
* @param fieldId Field Id of the ApplicationStartInfo as defined in the parent message
* @hide
*/
+ // LINT.IfChange(write_proto)
public void writeToProto(ProtoOutputStream proto, long fieldId) throws IOException {
final long token = proto.start(fieldId);
proto.write(ApplicationStartInfoProto.PID, mPid);
@@ -884,6 +889,7 @@ public final class ApplicationStartInfo implements Parcelable {
proto.write(ApplicationStartInfoProto.START_COMPONENT, mStartComponent);
proto.end(token);
}
+ // LINT.ThenChange(:read_proto)
/**
* Read from a protocol buffer input stream. Protocol buffer message definition at {@link
@@ -893,6 +899,7 @@ public final class ApplicationStartInfo implements Parcelable {
* @param fieldId Field Id of the ApplicationStartInfo as defined in the parent message
* @hide
*/
+ // LINT.IfChange(read_proto)
public void readFromProto(ProtoInputStream proto, long fieldId)
throws IOException, WireTypeMismatchException, ClassNotFoundException {
final long token = proto.start(fieldId);
@@ -976,6 +983,7 @@ public final class ApplicationStartInfo implements Parcelable {
}
proto.end(token);
}
+ // LINT.ThenChange(:write_proto)
/** @hide */
public void dump(@NonNull PrintWriter pw, @Nullable String prefix, @Nullable String seqSuffix,
diff --git a/core/java/android/app/DisabledWallpaperManager.java b/core/java/android/app/DisabledWallpaperManager.java
index 233dc75b810f..087bcd8620e4 100644
--- a/core/java/android/app/DisabledWallpaperManager.java
+++ b/core/java/android/app/DisabledWallpaperManager.java
@@ -177,13 +177,6 @@ final class DisabledWallpaperManager extends WallpaperManager {
}
@Override
- @NonNull
- public SparseArray<Rect> getBitmapCrops(int which) {
- unsupported();
- return new SparseArray<>();
- }
-
- @Override
public List<Rect> getBitmapCrops(@NonNull Point bitmapSize, @NonNull List<Point> displaySizes,
@Nullable Map<Point, Rect> cropHints) {
return unsupported();
diff --git a/core/java/android/app/DreamManager.java b/core/java/android/app/DreamManager.java
index 4ac40a1f77b2..c597a9dcae7e 100644
--- a/core/java/android/app/DreamManager.java
+++ b/core/java/android/app/DreamManager.java
@@ -234,4 +234,19 @@ public class DreamManager {
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Notifies dream manager of device postured state, which may affect dream enablement.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_ALLOW_DREAM_WHEN_POSTURED)
+ @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE)
+ public void setDevicePostured(boolean isPostured) {
+ try {
+ mService.setDevicePostured(isPostured);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 0451ac0d6897..1738a92b7672 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -114,6 +114,7 @@ interface INotificationManager
NotificationChannel getNotificationChannelForPackage(String pkg, int uid, String channelId, String conversationId, boolean includeDeleted);
void deleteNotificationChannel(String pkg, String channelId);
ParceledListSlice getNotificationChannels(String callingPkg, String targetPkg, int userId);
+ ParceledListSlice getOrCreateNotificationChannels(String callingPkg, String targetPkg, int userId, boolean createPrefsIfNeeded);
ParceledListSlice getNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);
int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);
int getDeletedChannelCount(String pkg, int uid);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 3c37b449c3a8..93d751cb9402 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -6627,7 +6627,20 @@ public class Notification implements Parcelable
*/
@Deprecated
public RemoteViews createContentView() {
- return createContentView(false /* increasedheight */ );
+ if (useExistingRemoteView(mN.contentView)) {
+ return fullyCustomViewRequiresDecoration(false /* fromStyle */)
+ ? minimallyDecoratedContentView(mN.contentView) : mN.contentView;
+ } else if (mStyle != null) {
+ final RemoteViews styleView = mStyle.makeContentView();
+ if (styleView != null) {
+ return fullyCustomViewRequiresDecoration(true /* fromStyle */)
+ ? minimallyDecoratedContentView(styleView) : styleView;
+ }
+ }
+ StandardTemplateParams p = mParams.reset()
+ .viewType(StandardTemplateParams.VIEW_TYPE_NORMAL)
+ .fillTextsFrom(this);
+ return applyStandardTemplate(getCollapsedBaseLayoutResource(), p, null /* result */);
}
// This code is executed on behalf of other apps' notifications, sometimes even by 3p apps,
@@ -6688,33 +6701,6 @@ public class Notification implements Parcelable
return standard;
}
- /**
- * Construct a RemoteViews for the smaller content view.
- *
- * @param increasedHeight true if this layout be created with an increased height. Some
- * styles may support showing more then just that basic 1U size
- * and the system may decide to render important notifications
- * slightly bigger even when collapsed.
- *
- * @hide
- */
- public RemoteViews createContentView(boolean increasedHeight) {
- if (useExistingRemoteView(mN.contentView)) {
- return fullyCustomViewRequiresDecoration(false /* fromStyle */)
- ? minimallyDecoratedContentView(mN.contentView) : mN.contentView;
- } else if (mStyle != null) {
- final RemoteViews styleView = mStyle.makeContentView(increasedHeight);
- if (styleView != null) {
- return fullyCustomViewRequiresDecoration(true /* fromStyle */)
- ? minimallyDecoratedContentView(styleView) : styleView;
- }
- }
- StandardTemplateParams p = mParams.reset()
- .viewType(StandardTemplateParams.VIEW_TYPE_NORMAL)
- .fillTextsFrom(this);
- return applyStandardTemplate(getCollapsedBaseLayoutResource(), p, null /* result */);
- }
-
private boolean useExistingRemoteView(RemoteViews customContent) {
if (customContent == null) {
return false;
@@ -6850,48 +6836,13 @@ public class Notification implements Parcelable
}
/**
- * Construct a RemoteViews for the final heads-up notification layout.
- *
- * @param increasedHeight true if this layout be created with an increased height. Some
- * styles may support showing more then just that basic 1U size
- * and the system may decide to render important notifications
- * slightly bigger even when collapsed.
- *
- * @hide
- */
- public RemoteViews createHeadsUpContentView(boolean increasedHeight) {
- if (useExistingRemoteView(mN.headsUpContentView)) {
- return fullyCustomViewRequiresDecoration(false /* fromStyle */)
- ? minimallyDecoratedHeadsUpContentView(mN.headsUpContentView)
- : mN.headsUpContentView;
- } else if (mStyle != null) {
- final RemoteViews styleView = mStyle.makeHeadsUpContentView(increasedHeight);
- if (styleView != null) {
- return fullyCustomViewRequiresDecoration(true /* fromStyle */)
- ? minimallyDecoratedHeadsUpContentView(styleView) : styleView;
- }
- } else if (mActions.size() == 0) {
- return null;
- }
-
- // We only want at most a single remote input history to be shown here, otherwise
- // the content would become squished.
- StandardTemplateParams p = mParams.reset()
- .viewType(StandardTemplateParams.VIEW_TYPE_HEADS_UP)
- .fillTextsFrom(this)
- .setMaxRemoteInputHistory(1);
- return applyStandardTemplateWithActions(getHeadsUpBaseLayoutResource(), p,
- null /* result */);
- }
-
- /**
* Construct a RemoteViews for the final compact heads-up notification layout.
* @hide
*/
public RemoteViews createCompactHeadsUpContentView() {
// Don't show compact heads up for FSI notifications.
if (mN.fullScreenIntent != null) {
- return createHeadsUpContentView(/* increasedHeight= */ false);
+ return createHeadsUpContentView();
}
if (mStyle != null) {
@@ -6929,7 +6880,28 @@ public class Notification implements Parcelable
*/
@Deprecated
public RemoteViews createHeadsUpContentView() {
- return createHeadsUpContentView(false /* useIncreasedHeight */);
+ if (useExistingRemoteView(mN.headsUpContentView)) {
+ return fullyCustomViewRequiresDecoration(false /* fromStyle */)
+ ? minimallyDecoratedHeadsUpContentView(mN.headsUpContentView)
+ : mN.headsUpContentView;
+ } else if (mStyle != null) {
+ final RemoteViews styleView = mStyle.makeHeadsUpContentView();
+ if (styleView != null) {
+ return fullyCustomViewRequiresDecoration(true /* fromStyle */)
+ ? minimallyDecoratedHeadsUpContentView(styleView) : styleView;
+ }
+ } else if (mActions.size() == 0) {
+ return null;
+ }
+
+ // We only want at most a single remote input history to be shown here, otherwise
+ // the content would become squished.
+ StandardTemplateParams p = mParams.reset()
+ .viewType(StandardTemplateParams.VIEW_TYPE_HEADS_UP)
+ .fillTextsFrom(this)
+ .setMaxRemoteInputHistory(1);
+ return applyStandardTemplateWithActions(getHeadsUpBaseLayoutResource(), p,
+ null /* result */);
}
/**
@@ -8236,10 +8208,9 @@ public class Notification implements Parcelable
* Construct a Style-specific RemoteViews for the collapsed notification layout.
* The default implementation has nothing additional to add.
*
- * @param increasedHeight true if this layout be created with an increased height.
* @hide
*/
- public RemoteViews makeContentView(boolean increasedHeight) {
+ public RemoteViews makeContentView() {
return null;
}
@@ -8254,10 +8225,9 @@ public class Notification implements Parcelable
/**
* Construct a Style-specific RemoteViews for the final HUN layout.
*
- * @param increasedHeight true if this layout be created with an increased height.
* @hide
*/
- public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
+ public RemoteViews makeHeadsUpContentView() {
return null;
}
@@ -8543,9 +8513,9 @@ public class Notification implements Parcelable
* @hide
*/
@Override
- public RemoteViews makeContentView(boolean increasedHeight) {
+ public RemoteViews makeContentView() {
if (mPictureIcon == null || !mShowBigPictureWhenCollapsed) {
- return super.makeContentView(increasedHeight);
+ return super.makeContentView();
}
StandardTemplateParams p = mBuilder.mParams.reset()
@@ -8559,9 +8529,9 @@ public class Notification implements Parcelable
* @hide
*/
@Override
- public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
+ public RemoteViews makeHeadsUpContentView() {
if (mPictureIcon == null || !mShowBigPictureWhenCollapsed) {
- return super.makeHeadsUpContentView(increasedHeight);
+ return super.makeHeadsUpContentView();
}
StandardTemplateParams p = mBuilder.mParams.reset()
@@ -8792,35 +8762,6 @@ public class Notification implements Parcelable
}
/**
- * @param increasedHeight true if this layout be created with an increased height.
- *
- * @hide
- */
- @Override
- public RemoteViews makeContentView(boolean increasedHeight) {
- if (increasedHeight) {
- ArrayList<Action> originalActions = mBuilder.mActions;
- mBuilder.mActions = new ArrayList<>();
- RemoteViews remoteViews = makeExpandedContentView();
- mBuilder.mActions = originalActions;
- return remoteViews;
- }
- return super.makeContentView(increasedHeight);
- }
-
- /**
- * @hide
- */
- @Override
- public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
- if (increasedHeight && mBuilder.mActions.size() > 0) {
- // TODO(b/163626038): pass VIEW_TYPE_HEADS_UP?
- return makeExpandedContentView();
- }
- return super.makeHeadsUpContentView(increasedHeight);
- }
-
- /**
* @hide
*/
public RemoteViews makeExpandedContentView() {
@@ -9404,7 +9345,7 @@ public class Notification implements Parcelable
* @hide
*/
@Override
- public RemoteViews makeContentView(boolean increasedHeight) {
+ public RemoteViews makeContentView() {
// All messaging templates contain the actions
ArrayList<Action> originalActions = mBuilder.mActions;
try {
@@ -9649,7 +9590,7 @@ public class Notification implements Parcelable
* @hide
*/
@Override
- public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
+ public RemoteViews makeHeadsUpContentView() {
return makeMessagingView(StandardTemplateParams.VIEW_TYPE_HEADS_UP);
}
@@ -10484,7 +10425,7 @@ public class Notification implements Parcelable
* @hide
*/
@Override
- public RemoteViews makeContentView(boolean increasedHeight) {
+ public RemoteViews makeContentView() {
return makeMediaContentView(null /* customContent */);
}
@@ -10500,7 +10441,7 @@ public class Notification implements Parcelable
* @hide
*/
@Override
- public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
+ public RemoteViews makeHeadsUpContentView() {
return makeMediaContentView(null /* customContent */);
}
@@ -10913,7 +10854,7 @@ public class Notification implements Parcelable
* @hide
*/
@Override
- public RemoteViews makeContentView(boolean increasedHeight) {
+ public RemoteViews makeContentView() {
return makeCallLayout(StandardTemplateParams.VIEW_TYPE_NORMAL);
}
@@ -10921,7 +10862,7 @@ public class Notification implements Parcelable
* @hide
*/
@Override
- public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
+ public RemoteViews makeHeadsUpContentView() {
return makeCallLayout(StandardTemplateParams.VIEW_TYPE_HEADS_UP);
}
@@ -10932,7 +10873,7 @@ public class Notification implements Parcelable
@Override
public RemoteViews makeCompactHeadsUpContentView() {
// Use existing heads up for call style.
- return makeHeadsUpContentView(false);
+ return makeHeadsUpContentView();
}
/**
@@ -11701,7 +11642,7 @@ public class Notification implements Parcelable
* @hide
*/
@Override
- public RemoteViews makeContentView(boolean increasedHeight) {
+ public RemoteViews makeContentView() {
final StandardTemplateParams p = mBuilder.mParams.reset()
.viewType(StandardTemplateParams.VIEW_TYPE_NORMAL)
.hideProgress(true)
@@ -11713,7 +11654,7 @@ public class Notification implements Parcelable
* @hide
*/
@Override
- public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
+ public RemoteViews makeHeadsUpContentView() {
final StandardTemplateParams p = mBuilder.mParams.reset()
.viewType(StandardTemplateParams.VIEW_TYPE_HEADS_UP)
.hideProgress(true)
@@ -12192,7 +12133,7 @@ public class Notification implements Parcelable
* @hide
*/
@Override
- public RemoteViews makeContentView(boolean increasedHeight) {
+ public RemoteViews makeContentView() {
return makeStandardTemplateWithCustomContent(mBuilder.mN.contentView);
}
@@ -12208,7 +12149,7 @@ public class Notification implements Parcelable
* @hide
*/
@Override
- public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
+ public RemoteViews makeHeadsUpContentView() {
return makeDecoratedHeadsUpContentView();
}
@@ -12328,7 +12269,7 @@ public class Notification implements Parcelable
* @hide
*/
@Override
- public RemoteViews makeContentView(boolean increasedHeight) {
+ public RemoteViews makeContentView() {
return makeMediaContentView(mBuilder.mN.contentView);
}
@@ -12347,7 +12288,7 @@ public class Notification implements Parcelable
* @hide
*/
@Override
- public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
+ public RemoteViews makeHeadsUpContentView() {
RemoteViews customContent = mBuilder.mN.headsUpContentView != null
? mBuilder.mN.headsUpContentView
: mBuilder.mN.contentView;
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index aede8aa70ede..24f2495d8f09 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -68,6 +68,7 @@ import android.service.notification.StatusBarNotification;
import android.service.notification.ZenDeviceEffects;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenPolicy;
+import android.text.TextUtils;
import android.util.Log;
import android.util.LruCache;
import android.util.Slog;
@@ -77,6 +78,8 @@ import com.android.internal.annotations.VisibleForTesting;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.time.Duration;
+import java.time.Instant;
import java.time.InstantSource;
import java.util.ArrayList;
import java.util.Arrays;
@@ -661,8 +664,10 @@ public class NotificationManager {
mCallNotificationEventCallbacks = new HashMap<>();
private final InstantSource mClock;
- private final RateEstimator mUpdateRateEstimator = new RateEstimator();
- private final RateEstimator mUnnecessaryCancelRateEstimator = new RateEstimator();
+ private final RateLimiter mUpdateRateLimiter = new RateLimiter("notify (update)",
+ MAX_NOTIFICATION_UPDATE_RATE);
+ private final RateLimiter mUnnecessaryCancelRateLimiter = new RateLimiter("cancel (dupe)",
+ MAX_NOTIFICATION_UNNECESSARY_CANCEL_RATE);
// Value is KNOWN_STATUS_ENQUEUED/_CANCELLED
private final LruCache<NotificationKey, Integer> mKnownNotifications = new LruCache<>(100);
private final Object mThrottleLock = new Object();
@@ -820,21 +825,16 @@ public class NotificationManager {
if (Flags.nmBinderPerfThrottleNotify()) {
NotificationKey key = new NotificationKey(user, pkg, tag, id);
- long now = mClock.millis();
synchronized (mThrottleLock) {
Integer status = mKnownNotifications.get(key);
if (status != null && status == KNOWN_STATUS_ENQUEUED
&& !notification.hasCompletedProgress()) {
- float updateRate = mUpdateRateEstimator.getRate(now);
- if (updateRate > MAX_NOTIFICATION_UPDATE_RATE) {
- Slog.w(TAG, "Shedding update of " + key
- + ", notification update maximum rate exceeded (" + updateRate
- + ")");
+ if (mUpdateRateLimiter.eventExceedsRate()) {
+ mUpdateRateLimiter.recordRejected(key);
return true;
}
- mUpdateRateEstimator.update(now);
+ mUpdateRateLimiter.recordAccepted();
}
-
mKnownNotifications.put(key, KNOWN_STATUS_ENQUEUED);
}
}
@@ -845,6 +845,51 @@ public class NotificationManager {
private record NotificationKey(@NonNull UserHandle user, @NonNull String pkg,
@Nullable String tag, int id) { }
+ /** Helper class to rate-limit Binder calls. */
+ private class RateLimiter {
+
+ private static final Duration RATE_LIMITER_LOG_INTERVAL = Duration.ofSeconds(5);
+
+ private final RateEstimator mInputRateEstimator;
+ private final RateEstimator mOutputRateEstimator;
+ private final String mName;
+ private final float mLimitRate;
+
+ private Instant mLogSilencedUntil;
+
+ private RateLimiter(String name, float limitRate) {
+ mInputRateEstimator = new RateEstimator();
+ mOutputRateEstimator = new RateEstimator();
+ mName = name;
+ mLimitRate = limitRate;
+ }
+
+ boolean eventExceedsRate() {
+ long nowMillis = mClock.millis();
+ mInputRateEstimator.update(nowMillis);
+ return mOutputRateEstimator.getRate(nowMillis) > mLimitRate;
+ }
+
+ void recordAccepted() {
+ mOutputRateEstimator.update(mClock.millis());
+ }
+
+ void recordRejected(NotificationKey key) {
+ Instant now = mClock.instant();
+ if (mLogSilencedUntil != null && now.isBefore(mLogSilencedUntil)) {
+ return;
+ }
+
+ long nowMillis = now.toEpochMilli();
+ Slog.w(TAG, TextUtils.formatSimple(
+ "Shedding %s of %s, rate limit (%s) exceeded: input %s, output would be %s",
+ mName, key, mLimitRate, mInputRateEstimator.getRate(nowMillis),
+ mOutputRateEstimator.getRate(nowMillis)));
+
+ mLogSilencedUntil = now.plus(RATE_LIMITER_LOG_INTERVAL);
+ }
+ }
+
private Notification fixNotification(Notification notification) {
String pkg = mContext.getPackageName();
// Fix the notification as best we can.
@@ -967,18 +1012,14 @@ public class NotificationManager {
private boolean discardCancel(UserHandle user, String pkg, @Nullable String tag, int id) {
if (Flags.nmBinderPerfThrottleNotify()) {
NotificationKey key = new NotificationKey(user, pkg, tag, id);
- long now = mClock.millis();
synchronized (mThrottleLock) {
Integer status = mKnownNotifications.get(key);
if (status != null && status == KNOWN_STATUS_CANCELLED) {
- float cancelRate = mUnnecessaryCancelRateEstimator.getRate(now);
- if (cancelRate > MAX_NOTIFICATION_UNNECESSARY_CANCEL_RATE) {
- Slog.w(TAG, "Shedding cancel of " + key
- + ", presumably unnecessary and maximum rate exceeded ("
- + cancelRate + ")");
+ if (mUnnecessaryCancelRateLimiter.eventExceedsRate()) {
+ mUnnecessaryCancelRateLimiter.recordRejected(key);
return true;
}
- mUnnecessaryCancelRateEstimator.update(now);
+ mUnnecessaryCancelRateLimiter.recordAccepted();
}
mKnownNotifications.put(key, KNOWN_STATUS_CANCELLED);
}
@@ -1211,7 +1252,8 @@ public class NotificationManager {
mNotificationChannelListCache.query(new NotificationChannelQuery(
mContext.getOpPackageName(),
mContext.getPackageName(),
- mContext.getUserId())));
+ mContext.getUserId(),
+ true))); // create (default channel) if needed
} else {
INotificationManager service = service();
try {
@@ -1239,7 +1281,8 @@ public class NotificationManager {
mNotificationChannelListCache.query(new NotificationChannelQuery(
mContext.getOpPackageName(),
mContext.getPackageName(),
- mContext.getUserId())));
+ mContext.getUserId(),
+ true))); // create (default channel) if needed
} else {
INotificationManager service = service();
try {
@@ -1263,9 +1306,10 @@ public class NotificationManager {
public List<NotificationChannel> getNotificationChannels() {
if (Flags.nmBinderPerfCacheChannels()) {
return mNotificationChannelListCache.query(new NotificationChannelQuery(
- mContext.getOpPackageName(),
- mContext.getPackageName(),
- mContext.getUserId()));
+ mContext.getOpPackageName(),
+ mContext.getPackageName(),
+ mContext.getUserId(),
+ false));
} else {
INotificationManager service = service();
try {
@@ -1405,8 +1449,8 @@ public class NotificationManager {
public List<NotificationChannel> apply(NotificationChannelQuery query) {
INotificationManager service = service();
try {
- return service.getNotificationChannels(query.callingPkg,
- query.targetPkg, query.userId).getList();
+ return service.getOrCreateNotificationChannels(query.callingPkg,
+ query.targetPkg, query.userId, query.createIfNeeded).getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1434,7 +1478,8 @@ public class NotificationManager {
private record NotificationChannelQuery(
String callingPkg,
String targetPkg,
- int userId) {}
+ int userId,
+ boolean createIfNeeded) {}
/**
* @hide
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index e7e9b0027812..660d88007c9a 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -22,7 +22,6 @@ import static com.android.internal.util.Preconditions.checkArgumentPositive;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.TestApi;
import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
@@ -77,7 +76,6 @@ import java.util.concurrent.atomic.AtomicLong;
* @param <Result> The class holding cache entries; use a boxed primitive if possible
* @hide
*/
-@TestApi
@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class PropertyInvalidatedCache<Query, Result> {
/**
@@ -95,7 +93,6 @@ public class PropertyInvalidatedCache<Query, Result> {
* This is a configuration class that customizes a cache instance.
* @hide
*/
- @TestApi
public static abstract class QueryHandler<Q,R> {
/**
* Compute a result given a query. The semantics are those of Functor.
@@ -134,7 +131,6 @@ public class PropertyInvalidatedCache<Query, Result> {
* the system has permissions to write properties with this module.
* @hide
*/
- @TestApi
public static final String MODULE_TEST = "test";
/**
@@ -142,18 +138,17 @@ public class PropertyInvalidatedCache<Query, Result> {
* the system processes.
* @hide
*/
- @TestApi
public static final String MODULE_SYSTEM = "system_server";
/**
* The module used for bluetooth caches.
* @hide
*/
- @TestApi
public static final String MODULE_BLUETOOTH = "bluetooth";
/**
* The module used for telephony caches.
+ * @hide
*/
public static final String MODULE_TELEPHONY = "telephony";
@@ -171,7 +166,6 @@ public class PropertyInvalidatedCache<Query, Result> {
* error message.
* @hide
*/
- @TestApi
public static @NonNull String createPropertyName(@NonNull String module,
@NonNull String apiName) {
char[] api = apiName.toCharArray();
@@ -1382,7 +1376,6 @@ public class PropertyInvalidatedCache<Query, Result> {
* @param computer The code to compute values that are not in the cache.
* @hide
*/
- @TestApi
public PropertyInvalidatedCache(int maxEntries, @NonNull String module, @NonNull String api,
@NonNull String cacheName, @NonNull QueryHandler<Query, Result> computer) {
this(new Args(module).maxEntries(maxEntries).api(api), cacheName, computer);
@@ -1409,7 +1402,7 @@ public class PropertyInvalidatedCache<Query, Result> {
* current logic does not care.
* @hide
*/
- @TestApi
+ @VisibleForTesting
public static void setTestMode(boolean mode) {
synchronized (sGlobalLock) {
if (sTestMode == mode) {
@@ -1450,7 +1443,6 @@ public class PropertyInvalidatedCache<Query, Result> {
* must be true when this method is called.
* @hide
*/
- @TestApi
public void testPropertyName() {
synchronized (sGlobalLock) {
if (sTestMode == false) {
@@ -1542,8 +1534,8 @@ public class PropertyInvalidatedCache<Query, Result> {
* be re-enabled.
* @hide
*/
- @TestApi
- public final void disableInstance() {
+ @VisibleForTesting
+ public void disableInstance() {
synchronized (mLock) {
mDisabled = true;
clear();
@@ -1579,8 +1571,8 @@ public class PropertyInvalidatedCache<Query, Result> {
* found in the list of disabled caches.
* @hide
*/
- @TestApi
- public final void forgetDisableLocal() {
+ @VisibleForTesting
+ public void forgetDisableLocal() {
synchronized (sGlobalLock) {
sDisabledKeys.remove(mCacheName);
}
@@ -1603,13 +1595,11 @@ public class PropertyInvalidatedCache<Query, Result> {
* property. Once disabled, a cache cannot be reenabled.
* @hide
*/
- @TestApi
public void disableForCurrentProcess() {
disableLocal(mCacheName);
}
/** @hide */
- @TestApi
public static void disableForCurrentProcess(@NonNull String cacheName) {
disableLocal(cacheName);
}
@@ -1618,8 +1608,8 @@ public class PropertyInvalidatedCache<Query, Result> {
* Return whether a cache instance is disabled.
* @hide
*/
- @TestApi
- public final boolean isDisabled() {
+ @VisibleForTesting
+ public boolean isDisabled() {
return mDisabled || !sEnabled;
}
@@ -1627,7 +1617,6 @@ public class PropertyInvalidatedCache<Query, Result> {
* Get a value from the cache or recompute it.
* @hide
*/
- @TestApi
public @Nullable Result query(@NonNull Query query) {
// Let access to mDisabled race: it's atomic anyway.
long currentNonce = (!isDisabled()) ? getCurrentNonce() : NONCE_DISABLED;
@@ -1767,8 +1756,8 @@ public class PropertyInvalidatedCache<Query, Result> {
* just use the static version of this function.
* @hide
*/
- @TestApi
- public final void disableSystemWide() {
+ @VisibleForTesting
+ public void disableSystemWide() {
disableSystemWide(mPropertyName);
}
@@ -1788,7 +1777,6 @@ public class PropertyInvalidatedCache<Query, Result> {
* to look up the NonceHandler for a given property name.
* @hide
*/
- @TestApi
public void invalidateCache() {
mNonce.invalidate();
}
@@ -1817,7 +1805,6 @@ public class PropertyInvalidatedCache<Query, Result> {
* Invalidate caches in all processes that are keyed for the module and api.
* @hide
*/
- @TestApi
public static void invalidateCache(@NonNull String module, @NonNull String api) {
invalidateCache(createPropertyName(module, api));
}
@@ -2059,7 +2046,6 @@ public class PropertyInvalidatedCache<Query, Result> {
* temporarily disable caching, use the corking mechanism.
* @hide
*/
- @TestApi
public static void disableForTestMode() {
Log.d(TAG, "disabling all caches in the process");
sEnabled = false;
@@ -2068,10 +2054,8 @@ public class PropertyInvalidatedCache<Query, Result> {
/**
* Report the disabled status of this cache instance. The return value does not
* reflect status of the property key.
- * @hide
*/
- @TestApi
- public boolean getDisabledState() {
+ private boolean getDisabledState() {
return isDisabled();
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 73ecc7199686..076f856635b5 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -19,7 +19,6 @@ package android.app;
import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE;
import static android.Manifest.permission.READ_WALLPAPER_INTERNAL;
import static android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT;
-import static android.app.Flags.FLAG_CUSTOMIZATION_PACKS_APIS;
import static android.app.Flags.FLAG_LIVE_WALLPAPER_CONTENT_HANDLING;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
@@ -343,32 +342,24 @@ public class WallpaperManager {
* Portrait orientation of most screens
* @hide
*/
- @FlaggedApi(FLAG_CUSTOMIZATION_PACKS_APIS)
- @SystemApi
public static final int ORIENTATION_PORTRAIT = 0;
/**
* Landscape orientation of most screens
* @hide
*/
- @FlaggedApi(FLAG_CUSTOMIZATION_PACKS_APIS)
- @SystemApi
public static final int ORIENTATION_LANDSCAPE = 1;
/**
* Portrait orientation with similar width and height (e.g. the inner screen of a foldable)
* @hide
*/
- @FlaggedApi(FLAG_CUSTOMIZATION_PACKS_APIS)
- @SystemApi
public static final int ORIENTATION_SQUARE_PORTRAIT = 2;
/**
* Landscape orientation with similar width and height (e.g. the inner screen of a foldable)
* @hide
*/
- @FlaggedApi(FLAG_CUSTOMIZATION_PACKS_APIS)
- @SystemApi
public static final int ORIENTATION_SQUARE_LANDSCAPE = 3;
/**
@@ -377,8 +368,6 @@ public class WallpaperManager {
* @return the corresponding {@link ScreenOrientation}.
* @hide
*/
- @FlaggedApi(FLAG_CUSTOMIZATION_PACKS_APIS)
- @SystemApi
public static @ScreenOrientation int getOrientation(@NonNull Point screenSize) {
float ratio = ((float) screenSize.x) / screenSize.y;
// ratios between 3/4 and 4/3 are considered square
@@ -1665,52 +1654,6 @@ public class WallpaperManager {
}
/**
- * For the current user, if the wallpaper of the specified destination is an ImageWallpaper,
- * return the custom crops of the wallpaper, that have been provided for example via
- * {@link #setStreamWithCrops}. These crops are relative to the original bitmap.
- * <p>
- * This method helps apps that change wallpapers provide an undo option. Calling
- * {@link #setStreamWithCrops(InputStream, SparseArray, boolean, int)} with this SparseArray and
- * the current original bitmap file, that can be obtained with {@link #getWallpaperFile(int,
- * boolean)} with {@code getCropped=false}, will exactly lead to the current wallpaper state.
- *
- * @param which wallpaper type. Must be either {@link #FLAG_SYSTEM} or {@link #FLAG_LOCK}.
- * @return A map from {{@link #ORIENTATION_PORTRAIT}, {@link #ORIENTATION_LANDSCAPE},
- * {@link #ORIENTATION_SQUARE_PORTRAIT}, {{@link #ORIENTATION_SQUARE_LANDSCAPE}}} to
- * Rect, representing the custom cropHints. The map can be empty and will only contains
- * entries for screen orientations for which a custom crop was provided. If no custom
- * crop is provided for an orientation, the system will infer the crop based on the
- * custom crops of the other orientations; or center-align the full image if no custom
- * crops are provided at all.
- * <p>
- * Return an empty map if the wallpaper is not an ImageWallpaper. Also return
- * an empty map when called with which={@link #FLAG_LOCK} if there is a shared
- * home + lock wallpaper.
- *
- * @hide
- */
- @FlaggedApi(FLAG_CUSTOMIZATION_PACKS_APIS)
- @TestApi
- @RequiresPermission(READ_WALLPAPER_INTERNAL)
- @NonNull
- public SparseArray<Rect> getBitmapCrops(@SetWallpaperFlags int which) {
- checkExactlyOneWallpaperFlagSet(which);
- try {
- Bundle bundle = sGlobals.mService.getCurrentBitmapCrops(which, mContext.getUserId());
- SparseArray<Rect> result = new SparseArray<>();
- if (bundle == null) return result;
- for (String key : bundle.keySet()) {
- int intKey = Integer.parseInt(key);
- Rect rect = bundle.getParcelable(key, Rect.class);
- result.put(intKey, rect);
- }
- return result;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* For preview purposes.
* Return how a bitmap of a given size would be cropped for a given list of display sizes, if
* it was set as wallpaper via {@link #setBitmapWithCrops(Bitmap, Map, boolean, int)} or
@@ -1955,8 +1898,6 @@ public class WallpaperManager {
* which={@link #FLAG_LOCK} if there is a shared home + lock wallpaper.
* @hide
*/
- @FlaggedApi(FLAG_CUSTOMIZATION_PACKS_APIS)
- @SystemApi
@Nullable
public ParcelFileDescriptor getWallpaperFile(@SetWallpaperFlags int which, boolean getCropped) {
return getWallpaperFile(which, mContext.getUserId(), getCropped);
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index b1db1379e400..edd17e8bb552 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -13,6 +13,13 @@ flag {
}
flag {
+ name: "notifications_redesign_themed_app_icons"
+ namespace: "systemui"
+ description: "Notifications Redesign: Experiment to make app icons in notifications themed"
+ bug: "371174789"
+}
+
+flag {
name: "notifications_redesign_templates"
namespace: "systemui"
description: "Notifications Redesign: Update notification templates"
@@ -174,16 +181,6 @@ flag {
}
flag {
- name: "update_ranking_time"
- namespace: "systemui"
- description: "Updates notification sorting criteria to highlight new content while maintaining stability"
- bug: "326016985"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "sort_section_by_time"
namespace: "systemui"
description: "Changes notification sort order to be by time within a section"
diff --git a/core/java/android/app/supervision/ISupervisionAppService.aidl b/core/java/android/app/supervision/ISupervisionAppService.aidl
new file mode 100644
index 000000000000..207fab90d015
--- /dev/null
+++ b/core/java/android/app/supervision/ISupervisionAppService.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.supervision;
+
+/**
+ * @hide
+ */
+interface ISupervisionAppService {
+ void onEnabled();
+ void onDisabled();
+}
diff --git a/core/java/android/app/supervision/SupervisionAppService.java b/core/java/android/app/supervision/SupervisionAppService.java
new file mode 100644
index 000000000000..4530be5c270a
--- /dev/null
+++ b/core/java/android/app/supervision/SupervisionAppService.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.supervision;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * Base class for a service that the {@code android.app.role.RoleManager.ROLE_SYSTEM_SUPERVISION}
+ * role holder must implement.
+ *
+ * @hide
+ */
+public class SupervisionAppService extends Service {
+ private final ISupervisionAppService mBinder = new ISupervisionAppService.Stub() {
+ @Override
+ public void onEnabled() {
+ SupervisionAppService.this.onEnabled();
+ }
+
+ @Override
+ public void onDisabled() {
+ SupervisionAppService.this.onDisabled();
+ }
+ };
+
+ @Override
+ public final IBinder onBind(Intent intent) {
+ return mBinder.asBinder();
+ }
+
+ /**
+ * Called when supervision is enabled.
+ */
+ public void onEnabled() {}
+
+ /**
+ * Called when supervision is disabled.
+ */
+ public void onDisabled() {}
+}
diff --git a/core/java/android/app/supervision/flags.aconfig b/core/java/android/app/supervision/flags.aconfig
index 1b0353274fb9..4ee3a0360b43 100644
--- a/core/java/android/app/supervision/flags.aconfig
+++ b/core/java/android/app/supervision/flags.aconfig
@@ -32,3 +32,11 @@ flag {
description: "Flag that deprecates supervision methods in DPM"
bug: "382034839"
}
+
+flag {
+ name: "enable_supervision_app_service"
+ is_exported: true
+ namespace: "supervision"
+ description: "Flag to enable the SupervisionAppService"
+ bug: "389123070"
+}
diff --git a/core/java/android/app/wallpaper.aconfig b/core/java/android/app/wallpaper.aconfig
index be9e286f5eb7..7aba172fad79 100644
--- a/core/java/android/app/wallpaper.aconfig
+++ b/core/java/android/app/wallpaper.aconfig
@@ -24,14 +24,6 @@ flag {
}
flag {
- name: "customization_packs_apis"
- is_exported: true
- namespace: "systemui"
- description: "Move APIs related to bitmap and crops to @SystemApi."
- bug: "372344184"
-}
-
-flag {
name: "accurate_wallpaper_downsampling"
namespace: "systemui"
description: "Accurate downsampling of wallpaper bitmap for high resolution images"
diff --git a/core/java/android/app/wallpaper/WallpaperDescription.java b/core/java/android/app/wallpaper/WallpaperDescription.java
index 999a5da870ad..a13af7f1ddcd 100644
--- a/core/java/android/app/wallpaper/WallpaperDescription.java
+++ b/core/java/android/app/wallpaper/WallpaperDescription.java
@@ -19,9 +19,7 @@ package android.app.wallpaper;
import static android.app.Flags.FLAG_LIVE_WALLPAPER_CONTENT_HANDLING;
import android.annotation.FlaggedApi;
-import android.annotation.SuppressLint;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.app.WallpaperInfo;
import android.app.WallpaperManager;
import android.app.WallpaperManager.ScreenOrientation;
@@ -514,8 +512,7 @@ public final class WallpaperDescription implements Parcelable {
* @hide
*/
@NonNull
- @TestApi
- @SuppressLint("MissingGetterMatchingBuilder")
+ @SystemApi
public Builder setCropHints(@NonNull Map<Point, Rect> cropHints) {
mCropHints = new SparseArray<>();
cropHints.forEach(
@@ -531,8 +528,7 @@ public final class WallpaperDescription implements Parcelable {
* @hide
*/
@NonNull
- @TestApi
- @SuppressLint("MissingGetterMatchingBuilder")
+ @SystemApi
public Builder setCropHints(@NonNull SparseArray<Rect> cropHints) {
mCropHints = cropHints;
return this;
diff --git a/core/java/android/companion/virtual/VirtualDevice.java b/core/java/android/companion/virtual/VirtualDevice.java
index b9e9afea8893..8ef4224975bf 100644
--- a/core/java/android/companion/virtual/VirtualDevice.java
+++ b/core/java/android/companion/virtual/VirtualDevice.java
@@ -20,11 +20,9 @@ import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CAMERA;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS;
-import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.companion.virtual.flags.Flags;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
@@ -34,8 +32,9 @@ import android.os.RemoteException;
* Details of a particular virtual device.
*
* <p>Read-only device representation exposing the properties of an existing virtual device.
+ *
+ * @see VirtualDeviceManager#registerVirtualDeviceListener
*/
-// TODO(b/310912420): Link to VirtualDeviceManager#registerVirtualDeviceListener from the docs
public final class VirtualDevice implements Parcelable {
private final @NonNull IVirtualDevice mVirtualDevice;
@@ -93,8 +92,8 @@ public final class VirtualDevice implements Parcelable {
* per device.
*
* @see Context#createDeviceContext
+ * @see #getPersistentDeviceId()
*/
- // TODO(b/310912420): Link to #getPersistentDeviceId from the docs
public int getDeviceId() {
return mId;
}
@@ -111,7 +110,6 @@ public final class VirtualDevice implements Parcelable {
* <p class="note">This identifier may not be unique across virtual devices, in case there are
* more than one virtual devices corresponding to the same physical device.
*/
- @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
public @Nullable String getPersistentDeviceId() {
return mPersistentId;
}
@@ -127,7 +125,6 @@ public final class VirtualDevice implements Parcelable {
* Returns the human-readable name of the virtual device, if defined, which is suitable to be
* shown in UI.
*/
- @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
public @Nullable CharSequence getDisplayName() {
return mDisplayName;
}
@@ -138,7 +135,6 @@ public final class VirtualDevice implements Parcelable {
* <p>The actual {@link android.view.Display} objects can be obtained by passing the returned
* IDs to {@link android.hardware.display.DisplayManager#getDisplay(int)}.</p>
*/
- @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
public @NonNull int[] getDisplayIds() {
try {
return mVirtualDevice.getDisplayIds();
@@ -157,7 +153,6 @@ public final class VirtualDevice implements Parcelable {
* @see Context#getDeviceId()
* @see Context#createDeviceContext(int)
*/
- @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
public boolean hasCustomSensorSupport() {
try {
return mVirtualDevice.getDevicePolicy(POLICY_TYPE_SENSORS) == DEVICE_POLICY_CUSTOM;
@@ -172,7 +167,6 @@ public final class VirtualDevice implements Parcelable {
* @hide
*/
@SystemApi
- @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
public boolean hasCustomAudioInputSupport() {
try {
return mVirtualDevice.hasCustomAudioInputSupport();
@@ -194,7 +188,6 @@ public final class VirtualDevice implements Parcelable {
* @hide
*/
@SystemApi
- @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
public boolean hasCustomCameraSupport() {
try {
return mVirtualDevice.getDevicePolicy(POLICY_TYPE_CAMERA) == DEVICE_POLICY_CUSTOM;
diff --git a/core/java/android/companion/virtual/VirtualDeviceInternal.java b/core/java/android/companion/virtual/VirtualDeviceInternal.java
index 311e24ba6254..3ef78affb7a5 100644
--- a/core/java/android/companion/virtual/VirtualDeviceInternal.java
+++ b/core/java/android/companion/virtual/VirtualDeviceInternal.java
@@ -32,7 +32,6 @@ import android.companion.virtual.audio.VirtualAudioDevice;
import android.companion.virtual.camera.VirtualCamera;
import android.companion.virtual.camera.VirtualCameraConfig;
import android.companion.virtual.sensor.VirtualSensor;
-import android.companion.virtualdevice.flags.Flags;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -473,14 +472,12 @@ public class VirtualDeviceInternal {
@Nullable VirtualAudioDevice.AudioConfigurationChangeCallback callback) {
if (mVirtualAudioDevice == null) {
try {
- Context context = mContext;
- if (Flags.deviceAwareRecordAudioPermission()) {
- // When using a default policy for audio device-aware RECORD_AUDIO permission
- // should not take effect, thus register policies with the default context.
- if (mVirtualDevice.getDevicePolicy(POLICY_TYPE_AUDIO) == DEVICE_POLICY_CUSTOM) {
- context = mContext.createDeviceContext(getDeviceId());
- }
- }
+ // When using a default policy for audio, the device-aware RECORD_AUDIO permission
+ // should not take effect, thus register policies with the default context.
+ final Context context =
+ mVirtualDevice.getDevicePolicy(POLICY_TYPE_AUDIO) == DEVICE_POLICY_CUSTOM
+ ? mContext.createDeviceContext(getDeviceId())
+ : mContext;
mVirtualAudioDevice = new VirtualAudioDevice(context, mVirtualDevice, display,
executor, callback, () -> mVirtualAudioDevice = null);
} catch (RemoteException e) {
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 73ea9f0462d5..99794d7f49fe 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -170,7 +170,6 @@ public final class VirtualDeviceManager {
* @hide
*/
@SystemApi
- @FlaggedApi(Flags.FLAG_PERSISTENT_DEVICE_ID_API)
public static final String PERSISTENT_DEVICE_ID_DEFAULT =
"default:" + Context.DEVICE_ID_DEFAULT;
@@ -224,10 +223,9 @@ public final class VirtualDeviceManager {
* existing virtual devices.</p>
*
* <p>Note that if a virtual device is closed and becomes invalid, the returned objects will
- * not be updated and may contain stale values.</p>
+ * not be updated and may contain stale values. Use a {@link VirtualDeviceListener} for real
+ * time updates of the availability of virtual devices.</p>
*/
- // TODO(b/310912420): Add "Use a VirtualDeviceListener for real time updates of the
- // availability of virtual devices." in the note paragraph above with a link annotation.
@NonNull
public List<android.companion.virtual.VirtualDevice> getVirtualDevices() {
if (mService == null) {
@@ -254,7 +252,6 @@ public final class VirtualDeviceManager {
* @return the virtual device with the requested ID, or {@code null} if no such device exists or
* it has already been closed.
*/
- @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
@Nullable
public android.companion.virtual.VirtualDevice getVirtualDevice(int deviceId) {
if (mService == null) {
@@ -279,7 +276,6 @@ public final class VirtualDeviceManager {
* @param listener The listener to add.
* @see #unregisterVirtualDeviceListener
*/
- @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
public void registerVirtualDeviceListener(
@NonNull @CallbackExecutor Executor executor,
@NonNull VirtualDeviceListener listener) {
@@ -307,7 +303,6 @@ public final class VirtualDeviceManager {
* @param listener The listener to unregister.
* @see #registerVirtualDeviceListener
*/
- @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
public void unregisterVirtualDeviceListener(@NonNull VirtualDeviceListener listener) {
if (mService == null) {
Log.w(TAG, "Failed to unregister listener; no virtual device manager service.");
@@ -390,10 +385,9 @@ public final class VirtualDeviceManager {
* @return the display name associated with the given persistent device ID, or {@code null} if
* the persistent ID is invalid or does not correspond to a virtual device.
*
+ * @see VirtualDevice#getPersistentDeviceId()
* @hide
*/
- // TODO(b/315481938): Link @see VirtualDevice#getPersistentDeviceId()
- @FlaggedApi(Flags.FLAG_PERSISTENT_DEVICE_ID_API)
@SystemApi
@Nullable
public CharSequence getDisplayNameForPersistentDeviceId(@NonNull String persistentDeviceId) {
@@ -413,10 +407,9 @@ public final class VirtualDeviceManager {
* Returns all current persistent device IDs, including the ones for which no virtual device
* exists, as long as one may have existed or can be created.
*
+ * @see VirtualDevice#getPersistentDeviceId()
* @hide
*/
- // TODO(b/315481938): Link @see VirtualDevice#getPersistentDeviceId()
- @FlaggedApi(Flags.FLAG_PERSISTENT_DEVICE_ID_API)
@SystemApi
@NonNull
public Set<String> getAllPersistentDeviceIds() {
@@ -591,7 +584,6 @@ public final class VirtualDeviceManager {
/**
* Returns the persistent ID of this virtual device.
*/
- @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
public @Nullable String getPersistentDeviceId() {
return mVirtualDeviceInternal.getPersistentDeviceId();
}
@@ -780,7 +772,6 @@ public final class VirtualDeviceManager {
* @see VirtualDeviceParams#POLICY_TYPE_RECENTS
* @see VirtualDeviceParams#POLICY_TYPE_ACTIVITY
*/
- @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY)
public void setDevicePolicy(@VirtualDeviceParams.DynamicPolicyType int policyType,
@VirtualDeviceParams.DevicePolicy int devicePolicy) {
mVirtualDeviceInternal.setDevicePolicy(policyType, devicePolicy);
@@ -802,7 +793,6 @@ public final class VirtualDeviceManager {
* @see #removeActivityPolicyExemption(ComponentName)
* @see #setDevicePolicy
*/
- @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY)
public void addActivityPolicyExemption(@NonNull ComponentName componentName) {
addActivityPolicyExemption(new ActivityPolicyExemption.Builder()
.setComponentName(componentName)
@@ -825,7 +815,6 @@ public final class VirtualDeviceManager {
* @see #addActivityPolicyExemption(ComponentName)
* @see #setDevicePolicy
*/
- @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY)
public void removeActivityPolicyExemption(@NonNull ComponentName componentName) {
removeActivityPolicyExemption(new ActivityPolicyExemption.Builder()
.setComponentName(componentName)
@@ -1037,9 +1026,7 @@ public final class VirtualDeviceManager {
* @param config the touchscreen configurations for the virtual stylus.
*/
@NonNull
- @FlaggedApi(Flags.FLAG_VIRTUAL_STYLUS)
- public VirtualStylus createVirtualStylus(
- @NonNull VirtualStylusConfig config) {
+ public VirtualStylus createVirtualStylus(@NonNull VirtualStylusConfig config) {
return mVirtualDeviceInternal.createVirtualStylus(config);
}
@@ -1347,7 +1334,6 @@ public final class VirtualDeviceManager {
*
* @see #registerVirtualDeviceListener
*/
- @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
public interface VirtualDeviceListener {
/**
* Called whenever a new virtual device has been added to the system.
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index 2be27dabcf90..761e75bd9076 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -248,7 +248,6 @@ public final class VirtualDeviceParams implements Parcelable {
*/
// TODO(b/333443509): Update the documentation of custom policy and link to the new policy
// POLICY_TYPE_BLOCKED_ACTIVITY
- @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY)
public static final int POLICY_TYPE_ACTIVITY = 3;
/**
@@ -264,7 +263,6 @@ public final class VirtualDeviceParams implements Parcelable {
*
* @see android.hardware.display.DisplayManager#VIRTUAL_DISPLAY_FLAG_TRUSTED
*/
- @FlaggedApi(Flags.FLAG_CROSS_DEVICE_CLIPBOARD)
public static final int POLICY_TYPE_CLIPBOARD = 4;
/**
@@ -431,7 +429,6 @@ public final class VirtualDeviceParams implements Parcelable {
* @see Builder#setHomeComponent
* @see VirtualDisplayConfig#isHomeSupported()
*/
- @FlaggedApi(Flags.FLAG_VDM_CUSTOM_HOME)
@Nullable
public ComponentName getHomeComponent() {
return mHomeComponent;
@@ -926,7 +923,6 @@ public final class VirtualDeviceParams implements Parcelable {
*
* @see VirtualDisplayConfig#isHomeSupported()
*/
- @FlaggedApi(Flags.FLAG_VDM_CUSTOM_HOME)
@NonNull
public Builder setHomeComponent(@Nullable ComponentName homeComponent) {
mHomeComponent = homeComponent;
@@ -1282,33 +1278,31 @@ public final class VirtualDeviceParams implements Parcelable {
mVirtualSensorDirectChannelCallback);
}
- if (Flags.dynamicPolicy()) {
- switch (mDevicePolicies.get(POLICY_TYPE_ACTIVITY, -1)) {
- case DEVICE_POLICY_DEFAULT:
- if (mDefaultActivityPolicyConfigured
- && mDefaultActivityPolicy == ACTIVITY_POLICY_DEFAULT_BLOCKED) {
- throw new IllegalArgumentException(
- "DEVICE_POLICY_DEFAULT is explicitly configured for "
- + "POLICY_TYPE_ACTIVITY, which is exclusive with "
- + "setAllowedActivities.");
- }
- break;
- case DEVICE_POLICY_CUSTOM:
- if (mDefaultActivityPolicyConfigured
- && mDefaultActivityPolicy == ACTIVITY_POLICY_DEFAULT_ALLOWED) {
- throw new IllegalArgumentException(
- "DEVICE_POLICY_CUSTOM is explicitly configured for "
- + "POLICY_TYPE_ACTIVITY, which is exclusive with "
- + "setBlockedActivities.");
- }
- break;
- default:
- if (mDefaultActivityPolicyConfigured
- && mDefaultActivityPolicy == ACTIVITY_POLICY_DEFAULT_BLOCKED) {
- mDevicePolicies.put(POLICY_TYPE_ACTIVITY, DEVICE_POLICY_CUSTOM);
- }
- break;
- }
+ switch (mDevicePolicies.get(POLICY_TYPE_ACTIVITY, -1)) {
+ case DEVICE_POLICY_DEFAULT:
+ if (mDefaultActivityPolicyConfigured
+ && mDefaultActivityPolicy == ACTIVITY_POLICY_DEFAULT_BLOCKED) {
+ throw new IllegalArgumentException(
+ "DEVICE_POLICY_DEFAULT is explicitly configured for "
+ + "POLICY_TYPE_ACTIVITY, which is exclusive with "
+ + "setAllowedActivities.");
+ }
+ break;
+ case DEVICE_POLICY_CUSTOM:
+ if (mDefaultActivityPolicyConfigured
+ && mDefaultActivityPolicy == ACTIVITY_POLICY_DEFAULT_ALLOWED) {
+ throw new IllegalArgumentException(
+ "DEVICE_POLICY_CUSTOM is explicitly configured for "
+ + "POLICY_TYPE_ACTIVITY, which is exclusive with "
+ + "setBlockedActivities.");
+ }
+ break;
+ default:
+ if (mDefaultActivityPolicyConfigured
+ && mDefaultActivityPolicy == ACTIVITY_POLICY_DEFAULT_BLOCKED) {
+ mDevicePolicies.put(POLICY_TYPE_ACTIVITY, DEVICE_POLICY_CUSTOM);
+ }
+ break;
}
if (mDimDuration.compareTo(mScreenOffTimeout) > 0) {
@@ -1319,10 +1313,6 @@ public final class VirtualDeviceParams implements Parcelable {
mScreenOffTimeout = INFINITE_TIMEOUT;
}
- if (!Flags.crossDeviceClipboard()) {
- mDevicePolicies.delete(POLICY_TYPE_CLIPBOARD);
- }
-
if (!Flags.virtualCamera()) {
mDevicePolicies.delete(POLICY_TYPE_CAMERA);
}
diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig
index 84af84072f1b..6da2a073ec19 100644
--- a/core/java/android/companion/virtual/flags/flags.aconfig
+++ b/core/java/android/companion/virtual/flags/flags.aconfig
@@ -19,14 +19,6 @@ flag {
flag {
namespace: "virtual_devices"
- name: "device_aware_record_audio_permission"
- description: "Enable device-aware RECORD_AUDIO permission"
- bug: "291737188"
- is_fixed_read_only: true
-}
-
-flag {
- namespace: "virtual_devices"
name: "media_projection_keyguard_restrictions"
description: "Auto-stop MP when the device locks"
bug: "348335290"
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 01e24d81a7cd..469688265ae8 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -16,7 +16,6 @@
package android.content;
-import static android.app.sdksandbox.SdkSandboxManager.ACTION_START_SANDBOXED_ACTIVITY;
import static android.content.ContentProvider.maybeAddUserId;
import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE;
import static android.security.Flags.FLAG_FRP_ENFORCEMENT;
@@ -4215,6 +4214,17 @@ public class Intent implements Parcelable, Cloneable {
public static final String ACTION_USER_INFO_CHANGED =
"android.intent.action.USER_INFO_CHANGED";
+
+ /**
+ * Broadcast sent to the system when a user's information changes. Carries an extra
+ * {@link #EXTRA_USER_HANDLE} to indicate which user's information changed.
+ * This is only sent to permission protected manifest receivers. It is sent to all users.
+ * @hide
+ */
+ @BroadcastBehavior(includeBackground = true)
+ public static final String ACTION_USER_INFO_CHANGED_BACKGROUND =
+ "android.intent.action.USER_INFO_CHANGED_BACKGROUND";
+
/**
* Broadcast sent to the primary user when an associated managed profile is added (the profile
* was created and is ready to be used). Carries an extra {@link #EXTRA_USER} that specifies
@@ -5460,7 +5470,7 @@ public class Intent implements Parcelable, Cloneable {
/**
* Activities that can be safely invoked from a browser must support this
* category. For example, if the user is viewing a web page or an e-mail
- * and clicks on a link in the text, the Intent generated execute that
+ * and clicks on a link in the text, the Intent generated to execute that
* link will require the BROWSABLE category, so that only activities
* supporting this category will be considered as possible actions. By
* supporting this category, you are promising that there is nothing
@@ -13448,28 +13458,4 @@ public class Intent implements Parcelable, Cloneable {
public boolean isDocument() {
return (mFlags & FLAG_ACTIVITY_NEW_DOCUMENT) == FLAG_ACTIVITY_NEW_DOCUMENT;
}
-
- /**
- * @deprecated Use {@link SdkSandboxActivityAuthority#isSdkSandboxActivityIntent} instead.
- * Once the other API is finalized this method will be removed.
- *
- * TODO(b/300059435): remove as part of the cleanup.
- *
- * @hide
- */
- @Deprecated
- @android.ravenwood.annotation.RavenwoodThrow
- public boolean isSandboxActivity(@NonNull Context context) {
- if (mAction != null && mAction.equals(ACTION_START_SANDBOXED_ACTIVITY)) {
- return true;
- }
- final String sandboxPackageName = context.getPackageManager().getSdkSandboxPackageName();
- if (mPackage != null && mPackage.equals(sandboxPackageName)) {
- return true;
- }
- if (mComponent != null && mComponent.getPackageName().equals(sandboxPackageName)) {
- return true;
- }
- return false;
- }
}
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index a0c0f122497f..1724d9ff0deb 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -1932,6 +1932,9 @@ public class LauncherApps {
* caller should have normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES}
* permission and the {@link android.app.role.RoleManager#ROLE_HOME} role.
*
+ * <p>This callback will also receive changes to the {@link LauncherUserInfo#getUserConfig()},
+ * allowing clients to monitor updates to the user-specific configuration.
+ *
* @param callback The callback to register.
*/
// Alternatively, a system app can access this api for private profile if they've been granted
@@ -1950,6 +1953,9 @@ public class LauncherApps {
* caller should have normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES}
* permission and the {@link android.app.role.RoleManager#ROLE_HOME} role.
*
+ * <p>This callback will also receive changes to the {@link LauncherUserInfo#getUserConfig()},
+ * allowing clients to monitor updates to the user-specific configuration.
+ *
* @param callback The callback to register.
* @param handler that should be used to post callbacks on, may be null.
*/
diff --git a/core/java/android/credentials/flags.aconfig b/core/java/android/credentials/flags.aconfig
index 2161e10337c9..430ed2b68342 100644
--- a/core/java/android/credentials/flags.aconfig
+++ b/core/java/android/credentials/flags.aconfig
@@ -144,3 +144,13 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ namespace: "credential_manager"
+ name: "fix_metric_duplication_emits"
+ description: "Fixes duplicate emits in the original metric emit system."
+ bug: "362994633"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+} \ No newline at end of file
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index 78c8954cfe5f..030c883924a7 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -25,10 +25,15 @@ import android.database.DatabaseErrorHandler;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.os.FileUtils;
+import android.util.ArrayMap;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
import java.io.File;
+import java.io.IOException;
import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
/**
* A helper class to manage database creation and version management.
@@ -54,6 +59,13 @@ import java.util.Objects;
public abstract class SQLiteOpenHelper implements AutoCloseable {
private static final String TAG = SQLiteOpenHelper.class.getSimpleName();
+ // Every database file has a lock, saved in this map. The lock is held while the database is
+ // opened.
+ private static final ConcurrentHashMap<String, Object> sDbLock = new ConcurrentHashMap<>();
+
+ // The lock that this open helper instance must hold when the database is opened.
+ private final Object mLock;
+
private final Context mContext;
@UnsupportedAppUsage
private final String mName;
@@ -168,6 +180,14 @@ public abstract class SQLiteOpenHelper implements AutoCloseable {
mNewVersion = version;
mMinimumSupportedVersion = Math.max(0, minimumSupportedVersion);
setOpenParamsBuilder(openParamsBuilder);
+
+ Object lock = null;
+ if (!Flags.concurrentOpenHelper() || mName == null) {
+ lock = new Object();
+ } else {
+ lock = sDbLock.computeIfAbsent(mName, (String k) -> new Object());
+ }
+ mLock = lock;
}
/**
@@ -358,74 +378,77 @@ public abstract class SQLiteOpenHelper implements AutoCloseable {
SQLiteDatabase db = mDatabase;
try {
- mIsInitializing = true;
+ synchronized (mLock) {
+ mIsInitializing = true;
- if (db != null) {
- if (writable && db.isReadOnly()) {
- db.reopenReadWrite();
- }
- } else if (mName == null) {
- db = SQLiteDatabase.createInMemory(mOpenParamsBuilder.build());
- } else {
- final File filePath = mContext.getDatabasePath(mName);
- SQLiteDatabase.OpenParams params = mOpenParamsBuilder.build();
- try {
- db = SQLiteDatabase.openDatabase(filePath, params);
- // Keep pre-O-MR1 behavior by resetting file permissions to 660
- setFilePermissionsForDb(filePath.getPath());
- } catch (SQLException ex) {
- if (writable) {
- throw ex;
+ if (db != null) {
+ if (writable && db.isReadOnly()) {
+ db.reopenReadWrite();
+ }
+ } else if (mName == null) {
+ db = SQLiteDatabase.createInMemory(mOpenParamsBuilder.build());
+ } else {
+ final File filePath = mContext.getDatabasePath(mName);
+ SQLiteDatabase.OpenParams params = mOpenParamsBuilder.build();
+ try {
+ db = SQLiteDatabase.openDatabase(filePath, params);
+ // Keep pre-O-MR1 behavior by resetting file permissions to 660
+ setFilePermissionsForDb(filePath.getPath());
+ } catch (SQLException ex) {
+ if (writable) {
+ throw ex;
+ }
+ Log.e(TAG, "Couldn't open database for writing (will try read-only):", ex);
+ params = params.toBuilder()
+ .addOpenFlags(SQLiteDatabase.OPEN_READONLY).build();
+ db = SQLiteDatabase.openDatabase(filePath, params);
}
- Log.e(TAG, "Couldn't open database for writing (will try read-only):", ex);
- params = params.toBuilder().addOpenFlags(SQLiteDatabase.OPEN_READONLY).build();
- db = SQLiteDatabase.openDatabase(filePath, params);
}
- }
- onConfigure(db);
+ onConfigure(db);
- final int version = db.getVersion();
- if (version != mNewVersion) {
- if (db.isReadOnly()) {
- throw new SQLiteException("Can't upgrade read-only database from version " +
- db.getVersion() + " to " + mNewVersion + ": " + mName);
- }
-
- if (version > 0 && version < mMinimumSupportedVersion) {
- File databaseFile = new File(db.getPath());
- onBeforeDelete(db);
- db.close();
- if (SQLiteDatabase.deleteDatabase(databaseFile)) {
- mIsInitializing = false;
- return getDatabaseLocked(writable);
- } else {
- throw new IllegalStateException("Unable to delete obsolete database "
- + mName + " with version " + version);
+ final int version = db.getVersion();
+ if (version != mNewVersion) {
+ if (db.isReadOnly()) {
+ throw new SQLiteException("Can't upgrade read-only database from version "
+ + db.getVersion() + " to " + mNewVersion + ": " + mName);
}
- } else {
- db.beginTransaction();
- try {
- if (version == 0) {
- onCreate(db);
+
+ if (version > 0 && version < mMinimumSupportedVersion) {
+ File databaseFile = new File(db.getPath());
+ onBeforeDelete(db);
+ db.close();
+ if (SQLiteDatabase.deleteDatabase(databaseFile)) {
+ mIsInitializing = false;
+ return getDatabaseLocked(writable);
} else {
- if (version > mNewVersion) {
- onDowngrade(db, version, mNewVersion);
+ throw new IllegalStateException("Unable to delete obsolete database "
+ + mName + " with version " + version);
+ }
+ } else {
+ db.beginTransaction();
+ try {
+ if (version == 0) {
+ onCreate(db);
} else {
- onUpgrade(db, version, mNewVersion);
+ if (version > mNewVersion) {
+ onDowngrade(db, version, mNewVersion);
+ } else {
+ onUpgrade(db, version, mNewVersion);
+ }
}
+ db.setVersion(mNewVersion);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
}
- db.setVersion(mNewVersion);
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
}
}
- }
- onOpen(db);
- mDatabase = db;
- return db;
+ onOpen(db);
+ mDatabase = db;
+ return db;
+ }
} finally {
mIsInitializing = false;
if (db != null && db != mDatabase) {
diff --git a/core/java/android/database/sqlite/flags.aconfig b/core/java/android/database/sqlite/flags.aconfig
index d43a66904af8..1d17a51f3653 100644
--- a/core/java/android/database/sqlite/flags.aconfig
+++ b/core/java/android/database/sqlite/flags.aconfig
@@ -17,3 +17,12 @@ flag {
description: "SQLite APIs held back for Android 15"
bug: "279043253"
}
+
+flag {
+ name: "concurrent_open_helper"
+ is_exported: true
+ namespace: "system_performance"
+ is_fixed_read_only: false
+ description: "Make SQLiteOpenHelper thread-safe"
+ bug: "335904370"
+}
diff --git a/core/java/android/hardware/contexthub/HubEndpoint.java b/core/java/android/hardware/contexthub/HubEndpoint.java
index 25cdc508fdce..14911de6d032 100644
--- a/core/java/android/hardware/contexthub/HubEndpoint.java
+++ b/core/java/android/hardware/contexthub/HubEndpoint.java
@@ -107,6 +107,13 @@ public class HubEndpoint {
@GuardedBy("mLock")
private final SparseArray<HubEndpointSession> mActiveSessions = new SparseArray<>();
+ /*
+ * Internal interface used to invoke IContextHubEndpoint calls.
+ */
+ interface EndpointConsumer {
+ void accept(IContextHubEndpoint endpoint) throws RemoteException;
+ }
+
private final IContextHubEndpointCallback mServiceCallback =
new IContextHubEndpointCallback.Stub() {
@Override
@@ -115,20 +122,19 @@ public class HubEndpoint {
HubEndpointInfo initiator,
@Nullable String serviceDescriptor)
throws RemoteException {
- HubEndpointSession activeSession;
+ boolean sessionExists;
synchronized (mLock) {
- activeSession = mActiveSessions.get(sessionId);
+ sessionExists = mActiveSessions.contains(sessionId);
// TODO(b/378974199): Consider refactor these assertions
- if (activeSession != null) {
- Log.i(
+ if (sessionExists) {
+ Log.w(
TAG,
"onSessionOpenComplete: session already exists, id="
+ sessionId);
- return;
}
}
- if (mLifecycleCallback != null) {
+ if (!sessionExists && mLifecycleCallback != null) {
mLifecycleCallbackExecutor.execute(
() ->
processSessionOpenRequestResult(
@@ -142,96 +148,6 @@ public class HubEndpoint {
}
}
- private void processSessionOpenRequestResult(
- int sessionId,
- HubEndpointInfo initiator,
- @Nullable String serviceDescriptor,
- HubEndpointSessionResult result) {
- if (result == null) {
- throw new IllegalArgumentException(
- "HubEndpointSessionResult shouldn't be null.");
- }
-
- if (result.isAccepted()) {
- acceptSession(sessionId, initiator, serviceDescriptor);
- } else {
- Log.i(
- TAG,
- "Session "
- + sessionId
- + " from "
- + initiator
- + " was rejected, reason="
- + result.getReason());
- rejectSession(sessionId);
- }
-
- invokeCallbackFinished();
- }
-
- private void acceptSession(
- int sessionId,
- HubEndpointInfo initiator,
- @Nullable String serviceDescriptor) {
- if (mServiceToken == null || mAssignedHubEndpointInfo == null) {
- // No longer registered?
- return;
- }
-
- // Retrieve the active session
- HubEndpointSession activeSession;
- synchronized (mLock) {
- activeSession = mActiveSessions.get(sessionId);
- // TODO(b/378974199): Consider refactor these assertions
- if (activeSession != null) {
- Log.e(
- TAG,
- "onSessionOpenRequestResult: session already exists, id="
- + sessionId);
- return;
- }
-
- activeSession =
- new HubEndpointSession(
- sessionId,
- HubEndpoint.this,
- mAssignedHubEndpointInfo,
- initiator,
- serviceDescriptor);
- try {
- // oneway call to notify system service that the request is completed
- mServiceToken.openSessionRequestComplete(sessionId);
- } catch (RemoteException e) {
- Log.e(TAG, "onSessionOpenRequestResult: ", e);
- return;
- }
-
- mActiveSessions.put(sessionId, activeSession);
- }
-
- // Execute the callback
- activeSession.setOpened();
- if (mLifecycleCallback != null) {
- final HubEndpointSession finalActiveSession = activeSession;
- mLifecycleCallbackExecutor.execute(
- () -> mLifecycleCallback.onSessionOpened(finalActiveSession));
- }
- }
-
- private void rejectSession(int sessionId) {
- if (mServiceToken == null || mAssignedHubEndpointInfo == null) {
- // No longer registered?
- return;
- }
-
- try {
- mServiceToken.closeSession(
- sessionId, REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- }
-
@Override
public void onSessionOpenComplete(int sessionId) throws RemoteException {
final HubEndpointSession activeSession;
@@ -242,16 +158,15 @@ public class HubEndpoint {
}
// TODO(b/378974199): Consider refactor these assertions
if (activeSession == null) {
- Log.i(
+ Log.w(
TAG,
"onSessionOpenComplete: no pending session open request? id="
+ sessionId);
- return;
+ } else {
+ activeSession.setOpened();
}
- // Execute the callback
- activeSession.setOpened();
- if (mLifecycleCallback != null) {
+ if (activeSession != null && mLifecycleCallback != null) {
mLifecycleCallbackExecutor.execute(
() -> {
mLifecycleCallback.onSessionOpened(activeSession);
@@ -272,12 +187,11 @@ public class HubEndpoint {
}
// TODO(b/378974199): Consider refactor these assertions
if (activeSession == null) {
- Log.i(TAG, "onSessionClosed: session not active, id=" + sessionId);
- return;
+ Log.w(TAG, "onSessionClosed: session not active, id=" + sessionId);
}
// Execute the callback
- if (mLifecycleCallback != null) {
+ if (activeSession != null && mLifecycleCallback != null) {
mLifecycleCallbackExecutor.execute(
() -> {
mLifecycleCallback.onSessionClosed(activeSession, reason);
@@ -304,44 +218,120 @@ public class HubEndpoint {
activeSession = mActiveSessions.get(sessionId);
}
if (activeSession == null) {
- Log.i(TAG, "onMessageReceived: session not active, id=" + sessionId);
+ Log.w(TAG, "onMessageReceived: session not active, id=" + sessionId);
}
if (activeSession == null || mMessageCallback == null) {
- if (message.isResponseRequired()) {
- try {
- mServiceToken.sendMessageDeliveryStatus(
- sessionId,
- message.getMessageSequenceNumber(),
- ErrorCode.DESTINATION_NOT_FOUND);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- }
- return;
+ sendMessageDeliveryStatus(
+ sessionId, message, ErrorCode.DESTINATION_NOT_FOUND);
+ } else {
+ mMessageCallbackExecutor.execute(
+ () -> {
+ mMessageCallback.onMessageReceived(activeSession, message);
+ sendMessageDeliveryStatus(sessionId, message, ErrorCode.OK);
+ });
}
+ }
- // Execute the callback
- mMessageCallbackExecutor.execute(
- () -> {
- mMessageCallback.onMessageReceived(activeSession, message);
- if (message.isResponseRequired()) {
- try {
- mServiceToken.sendMessageDeliveryStatus(
+ private void sendMessageDeliveryStatus(
+ int sessionId, HubMessage message, byte errorCode) {
+ if (message.isResponseRequired()) {
+ invokeCallback(
+ (callback) ->
+ callback.sendMessageDeliveryStatus(
sessionId,
message.getMessageSequenceNumber(),
- ErrorCode.OK);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- }
- invokeCallbackFinished();
- });
+ errorCode));
+ }
+ invokeCallbackFinished();
+ }
+
+ private void processSessionOpenRequestResult(
+ int sessionId,
+ HubEndpointInfo initiator,
+ @Nullable String serviceDescriptor,
+ HubEndpointSessionResult result) {
+ if (result == null) {
+ throw new IllegalArgumentException(
+ "HubEndpointSessionResult shouldn't be null.");
+ }
+
+ if (result.isAccepted()) {
+ acceptSession(sessionId, initiator, serviceDescriptor);
+ } else {
+ Log.e(
+ TAG,
+ "Session "
+ + sessionId
+ + " from "
+ + initiator
+ + " was rejected, reason="
+ + result.getReason());
+ rejectSession(sessionId);
+ }
+
+ invokeCallbackFinished();
+ }
+
+ private void acceptSession(
+ int sessionId,
+ HubEndpointInfo initiator,
+ @Nullable String serviceDescriptor) {
+ // Retrieve the active session
+ HubEndpointSession activeSession;
+ synchronized (mLock) {
+ activeSession = mActiveSessions.get(sessionId);
+ // TODO(b/378974199): Consider refactor these assertions
+ if (activeSession != null) {
+ Log.e(
+ TAG,
+ "onSessionOpenRequestResult: session already exists, id="
+ + sessionId);
+ return;
+ }
+
+ activeSession =
+ new HubEndpointSession(
+ sessionId,
+ HubEndpoint.this,
+ mAssignedHubEndpointInfo,
+ initiator,
+ serviceDescriptor);
+
+ invokeCallback(
+ (callback) -> callback.openSessionRequestComplete(sessionId));
+ mActiveSessions.put(sessionId, activeSession);
+ }
+
+ // Execute the callback
+ activeSession.setOpened();
+ if (mLifecycleCallback != null) {
+ final HubEndpointSession finalActiveSession = activeSession;
+ mLifecycleCallbackExecutor.execute(
+ () -> mLifecycleCallback.onSessionOpened(finalActiveSession));
+ }
+ }
+
+ private void rejectSession(int sessionId) {
+ invokeCallback(
+ (callback) ->
+ callback.closeSession(
+ sessionId,
+ REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED));
}
private void invokeCallbackFinished() {
+ invokeCallback((callback) -> callback.onCallbackFinished());
+ }
+
+ private void invokeCallback(EndpointConsumer consumer) {
try {
- mServiceToken.onCallbackFinished();
+ consumer.accept(mServiceToken);
+ } catch (IllegalStateException e) {
+ // It's possible to hit this exception if the endpoint was unregistered
+ // while processing the callback. It's not a fatal error so we just log
+ // a warning.
+ Log.w(TAG, "IllegalStateException while calling callback", e);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
@@ -369,11 +359,6 @@ public class HubEndpoint {
/** @hide */
public void register(IContextHubService service) {
- // TODO(b/378974199): Consider refactor these assertions
- if (mServiceToken != null) {
- // Already registered
- return;
- }
try {
IContextHubEndpoint serviceToken =
service.registerEndpoint(
@@ -391,13 +376,6 @@ public class HubEndpoint {
/** @hide */
public void unregister() {
- IContextHubEndpoint serviceToken = mServiceToken;
- // TODO(b/378974199): Consider refactor these assertions
- if (serviceToken == null) {
- // Not yet registered
- return;
- }
-
try {
synchronized (mLock) {
// Don't call HubEndpointSession.close() here.
@@ -410,20 +388,11 @@ public class HubEndpoint {
} catch (RemoteException e) {
Log.e(TAG, "unregisterEndpoint: failed to unregister endpoint", e);
e.rethrowFromSystemServer();
- } finally {
- mServiceToken = null;
- mAssignedHubEndpointInfo = null;
}
}
/** @hide */
public void openSession(HubEndpointInfo destinationInfo, @Nullable String serviceDescriptor) {
- // TODO(b/378974199): Consider refactor these assertions
- if (mServiceToken == null || mAssignedHubEndpointInfo == null) {
- // No longer registered?
- return;
- }
-
HubEndpointSession newSession;
try {
synchronized (mLock) {
@@ -449,13 +418,6 @@ public class HubEndpoint {
/** @hide */
public void closeSession(HubEndpointSession session) {
- IContextHubEndpoint serviceToken = mServiceToken;
- // TODO(b/378974199): Consider refactor these assertions
- if (serviceToken == null || mAssignedHubEndpointInfo == null) {
- // Not registered
- return;
- }
-
synchronized (mLock) {
if (!mActiveSessions.contains(session.getId())) {
// Already closed?
@@ -466,8 +428,7 @@ public class HubEndpoint {
}
try {
- // Oneway notification to system service
- serviceToken.closeSession(session.getId(), REASON_CLOSE_ENDPOINT_SESSION_REQUESTED);
+ mServiceToken.closeSession(session.getId(), REASON_CLOSE_ENDPOINT_SESSION_REQUESTED);
} catch (RemoteException e) {
Log.e(TAG, "closeSession: failed to close session " + session, e);
e.rethrowFromSystemServer();
@@ -478,14 +439,8 @@ public class HubEndpoint {
HubEndpointSession session,
HubMessage message,
@Nullable IContextHubTransactionCallback transactionCallback) {
- IContextHubEndpoint serviceToken = mServiceToken;
- if (serviceToken == null) {
- // Not registered
- return;
- }
-
try {
- serviceToken.sendMessage(session.getId(), message, transactionCallback);
+ mServiceToken.sendMessage(session.getId(), message, transactionCallback);
} catch (RemoteException e) {
Log.e(TAG, "sendMessage: failed to send message session=" + session, e);
e.rethrowFromSystemServer();
diff --git a/core/java/android/hardware/devicestate/feature/flags.aconfig b/core/java/android/hardware/devicestate/feature/flags.aconfig
index 6230f4dbf6f4..44d662f2a4fc 100644
--- a/core/java/android/hardware/devicestate/feature/flags.aconfig
+++ b/core/java/android/hardware/devicestate/feature/flags.aconfig
@@ -38,4 +38,16 @@ flag {
description: "Enables Rear Display Mode V2, where the inner display shows the user a UI affordance for exiting the state"
bug: "372486634"
is_fixed_read_only: true
-} \ No newline at end of file
+}
+
+flag {
+ name: "device_state_configuration_flag"
+ is_exported: true
+ namespace: "windowing_sdk"
+ description: "Re-add flag parsing for device_state_configuration.xml configuration for devices that didn't update vendor images."
+ bug: "388366842"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 6716598f9e4c..0590a06f3f82 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -397,7 +397,6 @@ public final class DisplayManager {
* @see #createVirtualDisplay
* @hide
*/
- @FlaggedApi(android.companion.virtual.flags.Flags.FLAG_VDM_PUBLIC_APIS)
@SystemApi
public static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 1 << 7;
diff --git a/core/java/android/hardware/display/VirtualDisplayConfig.java b/core/java/android/hardware/display/VirtualDisplayConfig.java
index 72570553f78a..2a9ee7f07934 100644
--- a/core/java/android/hardware/display/VirtualDisplayConfig.java
+++ b/core/java/android/hardware/display/VirtualDisplayConfig.java
@@ -237,10 +237,9 @@ public final class VirtualDisplayConfig implements Parcelable {
* @see Builder#setHomeSupported
* @hide
*/
- @FlaggedApi(android.companion.virtual.flags.Flags.FLAG_VDM_CUSTOM_HOME)
@SystemApi
public boolean isHomeSupported() {
- return android.companion.virtual.flags.Flags.vdmCustomHome() && mIsHomeSupported;
+ return mIsHomeSupported;
}
/**
@@ -605,7 +604,6 @@ public final class VirtualDisplayConfig implements Parcelable {
* @see DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
* @hide
*/
- @FlaggedApi(android.companion.virtual.flags.Flags.FLAG_VDM_CUSTOM_HOME)
@SystemApi
@NonNull
public Builder setHomeSupported(boolean isHomeSupported) {
diff --git a/core/java/android/hardware/input/KeyGestureEvent.java b/core/java/android/hardware/input/KeyGestureEvent.java
index 4025242fd208..1a712d2b3f31 100644
--- a/core/java/android/hardware/input/KeyGestureEvent.java
+++ b/core/java/android/hardware/input/KeyGestureEvent.java
@@ -122,17 +122,11 @@ public final class KeyGestureEvent {
public static final int KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW = 69;
public static final int KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW = 70;
public static final int KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW = 71;
- public static final int KEY_GESTURE_TYPE_MAGNIFICATION_ZOOM_IN = 72;
- public static final int KEY_GESTURE_TYPE_MAGNIFICATION_ZOOM_OUT = 73;
- public static final int KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION = 74;
- public static final int KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK = 75;
- public static final int KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW = 76;
- public static final int KEY_GESTURE_TYPE_TOGGLE_DO_NOT_DISTURB = 77;
- public static final int KEY_GESTURE_TYPE_MAGNIFICATION_PAN_LEFT = 78;
- public static final int KEY_GESTURE_TYPE_MAGNIFICATION_PAN_RIGHT = 79;
- public static final int KEY_GESTURE_TYPE_MAGNIFICATION_PAN_UP = 80;
- public static final int KEY_GESTURE_TYPE_MAGNIFICATION_PAN_DOWN = 81;
- public static final int KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS = 82;
+ public static final int KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION = 72;
+ public static final int KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK = 73;
+ public static final int KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW = 74;
+ public static final int KEY_GESTURE_TYPE_TOGGLE_DO_NOT_DISTURB = 75;
+ public static final int KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS = 76;
public static final int FLAG_CANCELLED = 1;
@@ -220,16 +214,10 @@ public final class KeyGestureEvent {
KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW,
KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW,
- KEY_GESTURE_TYPE_MAGNIFICATION_ZOOM_IN,
- KEY_GESTURE_TYPE_MAGNIFICATION_ZOOM_OUT,
KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION,
KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK,
KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW,
KEY_GESTURE_TYPE_TOGGLE_DO_NOT_DISTURB,
- KEY_GESTURE_TYPE_MAGNIFICATION_PAN_LEFT,
- KEY_GESTURE_TYPE_MAGNIFICATION_PAN_RIGHT,
- KEY_GESTURE_TYPE_MAGNIFICATION_PAN_UP,
- KEY_GESTURE_TYPE_MAGNIFICATION_PAN_DOWN,
KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS,
})
@Retention(RetentionPolicy.SOURCE)
@@ -815,10 +803,6 @@ public final class KeyGestureEvent {
return "KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW";
case KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW:
return "KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW";
- case KEY_GESTURE_TYPE_MAGNIFICATION_ZOOM_IN:
- return "KEY_GESTURE_TYPE_MAGNIFICATION_ZOOM_IN";
- case KEY_GESTURE_TYPE_MAGNIFICATION_ZOOM_OUT:
- return "KEY_GESTURE_TYPE_MAGNIFICATION_ZOOM_OUT";
case KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION:
return "KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION";
case KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK:
@@ -827,14 +811,6 @@ public final class KeyGestureEvent {
return "KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW";
case KEY_GESTURE_TYPE_TOGGLE_DO_NOT_DISTURB:
return "KEY_GESTURE_TYPE_TOGGLE_DO_NOT_DISTURB";
- case KEY_GESTURE_TYPE_MAGNIFICATION_PAN_LEFT:
- return "KEY_GESTURE_TYPE_MAGNIFICATION_PAN_LEFT";
- case KEY_GESTURE_TYPE_MAGNIFICATION_PAN_RIGHT:
- return "KEY_GESTURE_TYPE_MAGNIFICATION_PAN_RIGHT";
- case KEY_GESTURE_TYPE_MAGNIFICATION_PAN_UP:
- return "KEY_GESTURE_TYPE_MAGNIFICATION_PAN_UP";
- case KEY_GESTURE_TYPE_MAGNIFICATION_PAN_DOWN:
- return "KEY_GESTURE_TYPE_MAGNIFICATION_PAN_DOWN";
case KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS:
return "KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS";
default:
diff --git a/core/java/android/hardware/input/VirtualStylus.java b/core/java/android/hardware/input/VirtualStylus.java
index 4b79bc482c7b..32aac2efb3c1 100644
--- a/core/java/android/hardware/input/VirtualStylus.java
+++ b/core/java/android/hardware/input/VirtualStylus.java
@@ -16,11 +16,9 @@
package android.hardware.input;
-import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.companion.virtual.IVirtualDevice;
-import android.companion.virtual.flags.Flags;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -34,7 +32,6 @@ import android.util.Log;
*
* @hide
*/
-@FlaggedApi(Flags.FLAG_VIRTUAL_STYLUS)
@SystemApi
public class VirtualStylus extends VirtualInputDevice {
/** @hide */
diff --git a/core/java/android/hardware/input/VirtualStylusButtonEvent.java b/core/java/android/hardware/input/VirtualStylusButtonEvent.java
index 8fcf561bedcd..9fe725a627b4 100644
--- a/core/java/android/hardware/input/VirtualStylusButtonEvent.java
+++ b/core/java/android/hardware/input/VirtualStylusButtonEvent.java
@@ -16,11 +16,9 @@
package android.hardware.input;
-import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
-import android.companion.virtual.flags.Flags;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -35,7 +33,6 @@ import java.lang.annotation.RetentionPolicy;
*
* @hide
*/
-@FlaggedApi(Flags.FLAG_VIRTUAL_STYLUS)
@SystemApi
public final class VirtualStylusButtonEvent implements Parcelable {
/** @hide */
@@ -128,7 +125,6 @@ public final class VirtualStylusButtonEvent implements Parcelable {
/**
* Builder for {@link VirtualStylusButtonEvent}.
*/
- @FlaggedApi(Flags.FLAG_VIRTUAL_STYLUS)
public static final class Builder {
@Action
diff --git a/core/java/android/hardware/input/VirtualStylusConfig.java b/core/java/android/hardware/input/VirtualStylusConfig.java
index 64cf1f56d8bc..3c56023fa6d3 100644
--- a/core/java/android/hardware/input/VirtualStylusConfig.java
+++ b/core/java/android/hardware/input/VirtualStylusConfig.java
@@ -16,11 +16,9 @@
package android.hardware.input;
-import android.annotation.FlaggedApi;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SystemApi;
-import android.companion.virtual.flags.Flags;
import android.os.Parcel;
import android.os.Parcelable;
@@ -29,7 +27,6 @@ import android.os.Parcelable;
*
* @hide
*/
-@FlaggedApi(Flags.FLAG_VIRTUAL_STYLUS)
@SystemApi
public final class VirtualStylusConfig extends VirtualTouchDeviceConfig implements Parcelable {
@@ -68,7 +65,6 @@ public final class VirtualStylusConfig extends VirtualTouchDeviceConfig implemen
/**
* Builder for creating a {@link VirtualStylusConfig}.
*/
- @FlaggedApi(Flags.FLAG_VIRTUAL_STYLUS)
public static final class Builder extends VirtualTouchDeviceConfig.Builder<Builder> {
/**
diff --git a/core/java/android/hardware/input/VirtualStylusMotionEvent.java b/core/java/android/hardware/input/VirtualStylusMotionEvent.java
index 0ac6f3aa3e15..fa0ff4f7eeab 100644
--- a/core/java/android/hardware/input/VirtualStylusMotionEvent.java
+++ b/core/java/android/hardware/input/VirtualStylusMotionEvent.java
@@ -16,12 +16,10 @@
package android.hardware.input;
-import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SystemApi;
-import android.companion.virtual.flags.Flags;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -38,7 +36,6 @@ import java.lang.annotation.RetentionPolicy;
*
* @hide
*/
-@FlaggedApi(Flags.FLAG_VIRTUAL_STYLUS)
@SystemApi
public final class VirtualStylusMotionEvent implements Parcelable {
private static final int TILT_MIN = -90;
@@ -209,7 +206,6 @@ public final class VirtualStylusMotionEvent implements Parcelable {
/**
* Builder for {@link VirtualStylusMotionEvent}.
*/
- @FlaggedApi(Flags.FLAG_VIRTUAL_STYLUS)
public static final class Builder {
@ToolType
diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig
index 7887c15a72ff..62126963cba4 100644
--- a/core/java/android/hardware/input/input_framework.aconfig
+++ b/core/java/android/hardware/input/input_framework.aconfig
@@ -178,6 +178,13 @@ flag {
}
flag {
+ name: "enable_display_color_inversion_key_gestures"
+ namespace: "input"
+ description: "Adds key gestures for display color inversion for accessibility needs"
+ bug: "383730505"
+}
+
+flag {
name: "enable_talkback_and_magnifier_key_gestures"
namespace: "input"
description: "Adds key gestures for talkback and magnifier"
diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
index d9969d8b9596..3026609ed5cb 100644
--- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java
+++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
@@ -36,7 +36,6 @@ import android.util.Printer;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.ravenwood.RavenwoodEnvironment;
import dalvik.annotation.optimization.NeverCompile;
@@ -1392,12 +1391,12 @@ public final class MessageQueue {
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
+ if (peek) {
+ return msg;
+ }
if (now >= msg.when) {
// Got a message.
mBlocked = false;
- if (peek) {
- return msg;
- }
if (prevMsg != null) {
prevMsg.next = msg.next;
if (prevMsg.next == null) {
diff --git a/core/java/android/os/IpcDataCache.java b/core/java/android/os/IpcDataCache.java
index a2e9314f6436..240bc4f74820 100644
--- a/core/java/android/os/IpcDataCache.java
+++ b/core/java/android/os/IpcDataCache.java
@@ -658,4 +658,74 @@ public class IpcDataCache<Query, Result> extends PropertyInvalidatedCache<Query,
}
});
}
+
+ /**
+ * The following APIs are exposed to support testing. They only forward the superclass but
+ * that means the superclass does not have to expose the APIs itself.
+ */
+
+ /**
+ * Stop disabling local caches with the same name as <this>. Any caches that are currently
+ * disabled remain disabled (the "disabled" setting is sticky). However, new caches with this
+ * name will not be disabled. It is not an error if the cache name is not found in the list
+ * of disabled caches.
+ * @hide
+ */
+ @TestApi
+ @Override
+ public final void forgetDisableLocal() {
+ super.forgetDisableLocal();
+ }
+
+ /**
+ * Return whether a cache instance is disabled.
+ * @hide
+ */
+ @TestApi
+ @Override
+ public final boolean isDisabled() {
+ return super.isDisabled();
+ }
+
+ /**
+ * This is an obsolete synonym for {@link #isDisabled()}.
+ * @hide
+ */
+ @TestApi
+ public boolean getDisabledState() {
+ return isDisabled();
+ }
+
+ /**
+ * Disable the use of this cache in this process. This method is used internally and during
+ * testing. To disable a cache in normal code, use disableProcessLocal().
+ * @hide
+ */
+ @TestApi
+ @Override
+ public final void disableInstance() {
+ super.disableInstance();
+ }
+
+ /**
+ * Disable all caches that use the property as the current cache.
+ * @hide
+ */
+ @TestApi
+ @Override
+ public final void disableSystemWide() {
+ super.disableSystemWide();
+ }
+
+ /**
+ * Enable or disable testing. The protocol requires that the mode toggle: for instance, it is
+ * illegal to clear the test mode if the test mode is already off. The purpose is solely to
+ * ensure that test clients do not forget to use the test mode properly, even though the
+ * current logic does not care.
+ * @hide
+ */
+ @TestApi
+ public static void setTestMode(boolean mode) {
+ PropertyInvalidatedCache.setTestMode(mode);
+ }
}
diff --git a/core/java/android/os/LegacyMessageQueue/MessageQueue.java b/core/java/android/os/LegacyMessageQueue/MessageQueue.java
index c0333e914b4d..d12d99a71251 100644
--- a/core/java/android/os/LegacyMessageQueue/MessageQueue.java
+++ b/core/java/android/os/LegacyMessageQueue/MessageQueue.java
@@ -16,7 +16,6 @@
package android.os;
-import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -754,12 +753,12 @@ public final class MessageQueue {
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
+ if (peek) {
+ return msg;
+ }
if (now >= msg.when) {
// Got a message.
mBlocked = false;
- if (peek) {
- return msg;
- }
if (prevMsg != null) {
prevMsg.next = msg.next;
if (prevMsg.next == null) {
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 012590510714..2fe4871e08dd 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -70,6 +70,13 @@ public final class Looper {
private static final String TAG = "Looper";
+ private static class NoImagePreloadHolder {
+ // Enable/Disable verbose logging with a system prop. e.g.
+ // adb shell 'setprop log.looper.slow.verbose false && stop && start'
+ private static final boolean sVerboseLogging =
+ SystemProperties.getBoolean("log.looper.slow.verbose", false);
+ }
+
// sThreadLocal.get() will return null unless you've called prepare().
@UnsupportedAppUsage
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
@@ -246,17 +253,21 @@ public final class Looper {
}
}
if (logSlowDelivery) {
+ boolean slow = false;
+
+ if (!me.mSlowDeliveryDetected || NoImagePreloadHolder.sVerboseLogging) {
+ slow = showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart,
+ "delivery", msg);
+ }
if (me.mSlowDeliveryDetected) {
- if ((dispatchStart - msg.when) <= 10) {
+ if (!slow && (dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
me.mSlowDeliveryDetected = false;
}
- } else {
- if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
- msg)) {
- // Once we write a slow delivery log, suppress until the queue drains.
- me.mSlowDeliveryDetected = true;
- }
+ } else if (slow) {
+ // A slow delivery is detected, suppressing further logs unless verbose logging
+ // is enabled.
+ me.mSlowDeliveryDetected = true;
}
}
if (logSlowDispatch) {
@@ -322,6 +333,23 @@ public final class Looper {
@android.ravenwood.annotation.RavenwoodReplace
private static int getThresholdOverride() {
+ // Allow overriding the threshold for all processes' main looper with a system prop.
+ // e.g. adb shell 'setprop log.looper.any.main.slow 1 && stop && start'
+ if (myLooper() == getMainLooper()) {
+ final int globalOverride = SystemProperties.getInt("log.looper.any.main.slow", -1);
+ if (globalOverride >= 0) {
+ return globalOverride;
+ }
+ }
+
+ // Allow overriding the threshold for all threads within a process with a system prop.
+ // e.g. adb shell 'setprop log.looper.1000.any.slow 1 && stop && start'
+ final int processOverride = SystemProperties.getInt("log.looper."
+ + Process.myUid() + ".any.slow", -1);
+ if (processOverride >= 0) {
+ return processOverride;
+ }
+
return SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 9435f4d59a2c..77b6d70339ab 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -351,4 +351,10 @@ public abstract class PowerManagerInternal {
* return false if ambient display is not available.
*/
public abstract boolean isAmbientDisplaySuppressed();
+
+ /**
+ * Notifies PowerManager that the device has entered a postured state (stationary + upright).
+ * This may affect dream eligibility.
+ */
+ public abstract void setDevicePostured(boolean isPostured);
}
diff --git a/core/java/android/os/TEST_MAPPING b/core/java/android/os/TEST_MAPPING
index effe5554aff4..48fa0c8277df 100644
--- a/core/java/android/os/TEST_MAPPING
+++ b/core/java/android/os/TEST_MAPPING
@@ -112,6 +112,32 @@
{
"file_patterns": ["Bugreport[^/]*\\.java"],
"name": "ShellTests"
+ },
+ {
+ "file_patterns": [
+ "CpuHeadroom[^/]*",
+ "GpuHeadroom[^/]*",
+ "health/SystemHealthManager\\.java"
+ ],
+ "name": "CtsOsTestCases",
+ "options": [
+ {"include-filter": "android.os.health.cts.HeadroomTest"},
+ {"exclude-annotation": "androidx.test.filters.FlakyTest"},
+ {"exclude-annotation": "org.junit.Ignore"}
+ ]
+ },
+ {
+ "file_patterns": [
+ "CpuHeadroom[^/]*",
+ "GpuHeadroom[^/]*",
+ "health/SystemHealthManager\\.java"
+ ],
+ "name": "FrameworksCoreTests",
+ "options": [
+ {"include-filter": "android.os.SystemHealthManagerUnitTest"},
+ {"exclude-annotation": "androidx.test.filters.FlakyTest"},
+ {"exclude-annotation": "org.junit.Ignore"}
+ ]
}
],
"ravenwood-presubmit": [
diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java
index febbfca56bfb..9d0e221bd9e7 100644
--- a/core/java/android/os/health/SystemHealthManager.java
+++ b/core/java/android/os/health/SystemHealthManager.java
@@ -344,11 +344,7 @@ public class SystemHealthManager {
|| !mHintManagerClientData.supportInfo.headroom.isCpuSupported) {
throw new UnsupportedOperationException();
}
- try {
- return mHintManager.getCpuHeadroomMinIntervalMillis();
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
+ return mHintManagerClientData.supportInfo.headroom.cpuMinIntervalMillis;
}
/**
@@ -366,11 +362,7 @@ public class SystemHealthManager {
|| !mHintManagerClientData.supportInfo.headroom.isGpuSupported) {
throw new UnsupportedOperationException();
}
- try {
- return mHintManager.getGpuHeadroomMinIntervalMillis();
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
+ return mHintManagerClientData.supportInfo.headroom.gpuMinIntervalMillis;
}
/**
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 343d7527ea98..518820430419 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -2045,7 +2045,7 @@ public final class PermissionManager {
if (deviceId == Context.DEVICE_ID_DEFAULT) {
persistentDeviceId = VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT;
- } else if (android.companion.virtual.flags.Flags.vdmPublicApis()) {
+ } else {
VirtualDeviceManager virtualDeviceManager = mContext.getSystemService(
VirtualDeviceManager.class);
if (virtualDeviceManager != null) {
@@ -2059,9 +2059,6 @@ public final class PermissionManager {
Slog.e(LOG_TAG, "Cannot find persistent device Id for " + deviceId);
}
}
- } else {
- Slog.e(LOG_TAG, "vdmPublicApis flag is not enabled when device Id " + deviceId
- + "is not default.");
}
return persistentDeviceId;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index baaaa464a4cf..73d1e1701eec 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1254,21 +1254,6 @@ public final class Settings {
"android.settings.TEMPERATURE_UNIT_SETTINGS";
/**
- * Activity Action: Show numbering system configuration settings.
- * <p>
- * Input: Nothing.
- * <p>
- * Output: After calling {@link android.app.Activity#startActivityForResult}, the callback
- * {@code onActivityResult} will have resultCode {@link android.app.Activity#RESULT_OK} if
- * the numbering system settings page is suitable to show on the UI. Otherwise, the result is
- * set to {@link android.app.Activity#RESULT_CANCELED}.
- */
- @FlaggedApi(Flags.FLAG_SYSTEM_REGIONAL_PREFERENCES_API_ENABLED)
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_NUMBERING_SYSTEM_SETTINGS =
- "android.settings.NUMBERING_SYSTEM_SETTINGS";
-
- /**
* Activity Action: Show measurement system configuration settings.
* <p>
* Input: Nothing.
@@ -12884,6 +12869,19 @@ public final class Settings {
*/
public static final String DISABLE_SECURE_WINDOWS = "disable_secure_windows";
+ /**
+ * Controls if the adaptive authentication feature should be disabled, which
+ * will attempt to lock the device after a number of consecutive authentication
+ * attempts fail.
+ *
+ * This can only be disabled on debuggable builds. Set to 1 to disable or 0 for the
+ * normal behavior.
+ *
+ * @hide
+ */
+ public static final String DISABLE_ADAPTIVE_AUTH_LIMIT_LOCK =
+ "disable_adaptive_auth_limit_lock";
+
/** @hide */
public static final int PRIVATE_SPACE_AUTO_LOCK_ON_DEVICE_LOCK = 0;
/** @hide */
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index 4a9e945e62a9..a5586227cbb3 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -155,4 +155,11 @@ flag {
description: "Feature flag to add the privileged flag to the SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE permission"
bug: "380120712"
is_fixed_read_only: true
-} \ No newline at end of file
+}
+
+flag {
+ name: "disable_adaptive_auth_counter_lock"
+ namespace: "biometrics"
+ description: "Flag to allow an adb secure setting to disable the adaptive auth lock"
+ bug: "371057865"
+}
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index 1c0a2c021bca..3ca9d937b0ca 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -53,6 +53,8 @@ interface IDreamManager {
void startDreamActivity(in Intent intent);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE)")
oneway void setDreamIsObscured(in boolean isObscured);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE)")
+ oneway void setDevicePostured(in boolean isPostured);
oneway void startDozingOneway(in IBinder token, int screenState, int reason,
float screenBrightnessFloat, int screenBrightnessInt,
boolean useNormalBrightnessForDoze);
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 146c2b6fa46e..105fa3ffd4cd 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -30,13 +30,17 @@ import android.metrics.LogMaker;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.Trace;
import android.os.UserHandle;
+import android.util.ArrayMap;
import com.android.internal.logging.InstanceId;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import static com.android.window.flags.Flags.enablePerDisplayPackageContextCacheInStatusbarNotif;
import java.util.ArrayList;
+import java.util.Map;
/**
* Class encapsulating a Notification. Sent by the NotificationManagerService to clients including
@@ -69,7 +73,15 @@ public class StatusBarNotification implements Parcelable {
// A small per-notification ID, used for statsd logging.
private InstanceId mInstanceId; // Not final, see setInstanceId()
+ /**
+ * @deprecated This field is only used when
+ * {@link enablePerDisplayPackageContextCacheInStatusbarNotif}
+ * is disabled.
+ */
+ @Deprecated
private Context mContext; // used for inflation & icon expansion
+ // Maps display id to context used for remote view content inflation and status bar icon.
+ private final Map<Integer, Context> mContextForDisplayId = new ArrayMap<>();
/** @hide */
public StatusBarNotification(String pkg, String opPkg, int id,
@@ -453,7 +465,11 @@ public class StatusBarNotification implements Parcelable {
* @hide
*/
public void clearPackageContext() {
- mContext = null;
+ if (enablePerDisplayPackageContextCacheInStatusbarNotif()) {
+ mContextForDisplayId.clear();
+ } else {
+ mContext = null;
+ }
}
/**
@@ -475,21 +491,42 @@ public class StatusBarNotification implements Parcelable {
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public Context getPackageContext(Context context) {
- if (mContext == null) {
- try {
- ApplicationInfo ai = context.getPackageManager()
- .getApplicationInfoAsUser(pkg, PackageManager.MATCH_UNINSTALLED_PACKAGES,
- getNormalizedUserId());
- mContext = context.createApplicationContext(ai,
- Context.CONTEXT_RESTRICTED);
- } catch (PackageManager.NameNotFoundException e) {
- mContext = null;
+ if (enablePerDisplayPackageContextCacheInStatusbarNotif()) {
+ if (context == null) return null;
+ return mContextForDisplayId.computeIfAbsent(context.getDisplayId(),
+ (displayId) -> createPackageContext(context));
+ } else {
+ if (mContext == null) {
+ try {
+ ApplicationInfo ai = context.getPackageManager()
+ .getApplicationInfoAsUser(pkg,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES,
+ getNormalizedUserId());
+ mContext = context.createApplicationContext(ai,
+ Context.CONTEXT_RESTRICTED);
+ } catch (PackageManager.NameNotFoundException e) {
+ mContext = null;
+ }
+ }
+ if (mContext == null) {
+ mContext = context;
}
+ return mContext;
}
- if (mContext == null) {
- mContext = context;
+ }
+
+ private Context createPackageContext(Context context) {
+ try {
+ Trace.beginSection("StatusBarNotification#createPackageContext");
+ ApplicationInfo ai = context.getPackageManager()
+ .getApplicationInfoAsUser(pkg, PackageManager.MATCH_UNINSTALLED_PACKAGES,
+ getNormalizedUserId());
+ return context.createApplicationContext(ai, Context.CONTEXT_RESTRICTED);
+ } catch (PackageManager.NameNotFoundException e) {
+ return context;
+ } finally {
+ Trace.endSection();
}
- return mContext;
}
/**
diff --git a/core/java/android/service/settings/preferences/SettingsPreferenceValue.java b/core/java/android/service/settings/preferences/SettingsPreferenceValue.java
index eea93b321e47..2e661b475dc9 100644
--- a/core/java/android/service/settings/preferences/SettingsPreferenceValue.java
+++ b/core/java/android/service/settings/preferences/SettingsPreferenceValue.java
@@ -34,8 +34,7 @@ import java.lang.annotation.RetentionPolicy;
* This objects represents a value that can be used for a particular settings preference.
* <p>The data type for the value will correspond to {@link #getType}. For possible types, see
* constants below, such as {@link #TYPE_BOOLEAN} and {@link #TYPE_STRING}.
- * Depending on the type, the corresponding getter will contain its value. All other getters will
- * return default values (boolean returns false, String returns null) so they should not be used.
+ * Depending on the type, the corresponding getter will contain its value.
* <p>See documentation on the constants for which getter method should be used.
*/
@FlaggedApi(Flags.FLAG_SETTINGS_CATALYST)
@@ -43,12 +42,7 @@ public final class SettingsPreferenceValue implements Parcelable {
@Type
private final int mType;
- private final boolean mBooleanValue;
- private final int mIntValue;
- private final long mLongValue;
- private final double mDoubleValue;
- @Nullable
- private final String mStringValue;
+ private final @Nullable Object mValue;
/**
* Returns the type indicator for Preference value.
@@ -59,39 +53,39 @@ public final class SettingsPreferenceValue implements Parcelable {
}
/**
- * Returns the boolean value for Preference if type is {@link #TYPE_BOOLEAN}.
+ * Returns the boolean value for Preference, the type must be {@link #TYPE_BOOLEAN}.
*/
public boolean getBooleanValue() {
- return mBooleanValue;
+ return (boolean) mValue;
}
/**
- * Returns the int value for Preference if type is {@link #TYPE_INT}.
+ * Returns the int value for Preference, the type must be {@link #TYPE_INT}.
*/
public int getIntValue() {
- return mIntValue;
+ return (int) mValue;
}
/**
- * Returns the long value for Preference if type is {@link #TYPE_LONG}.
+ * Returns the long value for Preference, the type must be {@link #TYPE_LONG}.
*/
public long getLongValue() {
- return mLongValue;
+ return (long) mValue;
}
/**
- * Returns the double value for Preference if type is {@link #TYPE_DOUBLE}.
+ * Returns the double value for Preference, the type must be {@link #TYPE_DOUBLE}.
*/
public double getDoubleValue() {
- return mDoubleValue;
+ return (double) mValue;
}
/**
- * Returns the string value for Preference if type is {@link #TYPE_STRING}.
+ * Returns the string value for Preference, the type must be {@link #TYPE_STRING}.
*/
@Nullable
public String getStringValue() {
- return mStringValue;
+ return (String) mValue;
}
/** @hide */
@@ -115,34 +109,47 @@ public final class SettingsPreferenceValue implements Parcelable {
public static final int TYPE_STRING = 3;
/** Value is of type int. Access via {@link #getIntValue}. */
public static final int TYPE_INT = 4;
+ /** Max type value. */
+ private static final int MAX_TYPE_VALUE = TYPE_INT;
private SettingsPreferenceValue(@NonNull Builder builder) {
mType = builder.mType;
- mBooleanValue = builder.mBooleanValue;
- mLongValue = builder.mLongValue;
- mDoubleValue = builder.mDoubleValue;
- mStringValue = builder.mStringValue;
- mIntValue = builder.mIntValue;
+ mValue = builder.mValue;
}
private SettingsPreferenceValue(@NonNull Parcel in) {
mType = in.readInt();
- mBooleanValue = in.readBoolean();
- mLongValue = in.readLong();
- mDoubleValue = in.readDouble();
- mStringValue = in.readString8();
- mIntValue = in.readInt();
+ if (mType == TYPE_BOOLEAN) {
+ mValue = in.readBoolean();
+ } else if (mType == TYPE_LONG) {
+ mValue = in.readLong();
+ } else if (mType == TYPE_DOUBLE) {
+ mValue = in.readDouble();
+ } else if (mType == TYPE_STRING) {
+ mValue = in.readString();
+ } else if (mType == TYPE_INT) {
+ mValue = in.readInt();
+ } else {
+ // throw exception immediately, further read to Parcel may be invalid
+ throw new IllegalStateException("Unknown type: " + mType);
+ }
}
/** @hide */
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mType);
- dest.writeBoolean(mBooleanValue);
- dest.writeLong(mLongValue);
- dest.writeDouble(mDoubleValue);
- dest.writeString8(mStringValue);
- dest.writeInt(mIntValue);
+ if (mType == TYPE_BOOLEAN) {
+ dest.writeBoolean(getBooleanValue());
+ } else if (mType == TYPE_LONG) {
+ dest.writeLong(getLongValue());
+ } else if (mType == TYPE_DOUBLE) {
+ dest.writeDouble(getDoubleValue());
+ } else if (mType == TYPE_STRING) {
+ dest.writeString(getStringValue());
+ } else if (mType == TYPE_INT) {
+ dest.writeInt(getIntValue());
+ }
}
/** @hide */
@@ -174,17 +181,16 @@ public final class SettingsPreferenceValue implements Parcelable {
public static final class Builder {
@Type
private final int mType;
- private boolean mBooleanValue;
- private long mLongValue;
- private double mDoubleValue;
- private String mStringValue;
- private int mIntValue;
+ private @Nullable Object mValue;
/**
* Create Builder instance.
* @param type type indicator for preference value
*/
public Builder(@Type int type) {
+ if (type < 0 || type > MAX_TYPE_VALUE) {
+ throw new IllegalArgumentException("Unknown type: " + type);
+ }
mType = type;
}
@@ -194,7 +200,8 @@ public final class SettingsPreferenceValue implements Parcelable {
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
public Builder setBooleanValue(boolean booleanValue) {
- mBooleanValue = booleanValue;
+ checkType(TYPE_BOOLEAN);
+ mValue = booleanValue;
return this;
}
@@ -203,7 +210,8 @@ public final class SettingsPreferenceValue implements Parcelable {
*/
@NonNull
public Builder setIntValue(int intValue) {
- mIntValue = intValue;
+ checkType(TYPE_INT);
+ mValue = intValue;
return this;
}
@@ -212,7 +220,8 @@ public final class SettingsPreferenceValue implements Parcelable {
*/
@NonNull
public Builder setLongValue(long longValue) {
- mLongValue = longValue;
+ checkType(TYPE_LONG);
+ mValue = longValue;
return this;
}
@@ -221,7 +230,8 @@ public final class SettingsPreferenceValue implements Parcelable {
*/
@NonNull
public Builder setDoubleValue(double doubleValue) {
- mDoubleValue = doubleValue;
+ checkType(TYPE_DOUBLE);
+ mValue = doubleValue;
return this;
}
@@ -230,10 +240,17 @@ public final class SettingsPreferenceValue implements Parcelable {
*/
@NonNull
public Builder setStringValue(@Nullable String stringValue) {
- mStringValue = stringValue;
+ checkType(TYPE_STRING);
+ mValue = stringValue;
return this;
}
+ private void checkType(int type) {
+ if (mType != type) {
+ throw new IllegalArgumentException("Type is: " + mType);
+ }
+ }
+
/**
* Constructs an immutable {@link SettingsPreferenceValue} object.
*/
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 990b099d616e..464756842caf 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -325,6 +325,7 @@ public abstract class WallpaperService extends Service {
IWindowSession mSession;
final Object mLock = new Object();
+ private final Object mSurfaceReleaseLock = new Object();
boolean mOffsetMessageEnqueued;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -1075,9 +1076,11 @@ public abstract class WallpaperService extends Service {
animator.setDuration(DIMMING_ANIMATION_DURATION_MS);
animator.addUpdateListener((ValueAnimator va) -> {
final float dimValue = (float) va.getAnimatedValue();
- if (mBbqSurfaceControl != null) {
- surfaceControlTransaction
- .setAlpha(mBbqSurfaceControl, 1 - dimValue).apply();
+ synchronized (mSurfaceReleaseLock) {
+ if (mBbqSurfaceControl != null && mBbqSurfaceControl.isValid()) {
+ surfaceControlTransaction
+ .setAlpha(mBbqSurfaceControl, 1 - dimValue).apply();
+ }
}
});
animator.addListener(new AnimatorListenerAdapter() {
@@ -2356,35 +2359,39 @@ public abstract class WallpaperService extends Service {
if (DEBUG) Log.v(TAG, "onDestroy(): " + this);
onDestroy();
- if (mCreated) {
- try {
- if (DEBUG) Log.v(TAG, "Removing window and destroying surface "
- + mSurfaceHolder.getSurface() + " of: " + this);
+ synchronized (mSurfaceReleaseLock) {
+ if (mCreated) {
+ try {
+ if (DEBUG) {
+ Log.v(TAG, "Removing window and destroying surface "
+ + mSurfaceHolder.getSurface() + " of: " + this);
+ }
- if (mInputEventReceiver != null) {
- mInputEventReceiver.dispose();
- mInputEventReceiver = null;
- }
+ if (mInputEventReceiver != null) {
+ mInputEventReceiver.dispose();
+ mInputEventReceiver = null;
+ }
- mSession.remove(mWindow.asBinder());
- } catch (RemoteException e) {
- }
- mSurfaceHolder.mSurface.release();
- if (mBlastBufferQueue != null) {
- mBlastBufferQueue.destroy();
- mBlastBufferQueue = null;
- }
- if (mBbqSurfaceControl != null) {
- new SurfaceControl.Transaction().remove(mBbqSurfaceControl).apply();
- mBbqSurfaceControl = null;
+ mSession.remove(mWindow.asBinder());
+ } catch (RemoteException e) {
+ }
+ mSurfaceHolder.mSurface.release();
+ if (mBlastBufferQueue != null) {
+ mBlastBufferQueue.destroy();
+ mBlastBufferQueue = null;
+ }
+ if (mBbqSurfaceControl != null) {
+ new SurfaceControl.Transaction().remove(mBbqSurfaceControl).apply();
+ mBbqSurfaceControl = null;
+ }
+ mCreated = false;
}
- mCreated = false;
- }
- if (mSurfaceControl != null) {
- mSurfaceControl.release();
- mSurfaceControl = null;
- mRelayoutResult = null;
+ if (mSurfaceControl != null) {
+ mSurfaceControl.release();
+ mSurfaceControl = null;
+ mRelayoutResult = null;
+ }
}
}
@@ -2417,9 +2424,10 @@ public abstract class WallpaperService extends Service {
Surface ret = null;
if (mBlastBufferQueue == null) {
- mBlastBufferQueue = new BLASTBufferQueue("Wallpaper", mBbqSurfaceControl,
- width, height, format);
+ mBlastBufferQueue = new BLASTBufferQueue("Wallpaper",
+ true /* updateDestinationFrame */);
mBlastBufferQueue.setApplyToken(mBbqApplyToken);
+ mBlastBufferQueue.update(mBbqSurfaceControl, width, height, format);
// We only return the Surface the first time, as otherwise
// it hasn't changed and there is no need to update.
ret = mBlastBufferQueue.createSurface();
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 3c53506990d1..323d83b92143 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1066,6 +1066,12 @@ public abstract class Layout {
var hasBgColorChanged = newBackground != bgPaint.getColor();
if (lineNum != mLastLineNum || hasBgColorChanged) {
+ // Skip processing if the character is a space or a tap to avoid
+ // rendering an abrupt, empty rectangle.
+ if (Character.isWhitespace(mText.charAt(index))) {
+ return;
+ }
+
// Draw what we have so far, then reset the rect and update its color
drawRect();
mLineBackground.set(left, top, right, bottom);
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 4fead2ad5246..6decd6d3a603 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -112,6 +112,7 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro
private Insets mPendingInsets;
private float mPendingFraction;
private boolean mFinished;
+ private boolean mCancelling;
private boolean mCancelled;
private boolean mShownOnFinish;
private float mCurrentAlpha = 1.0f;
@@ -371,7 +372,7 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro
mPendingInsets = mLayoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN
? mShownInsets : mHiddenInsets;
mPendingAlpha = 1f;
- mPendingFraction = 1f;
+ mCancelling = true;
applyChangeInsets(null);
mCancelled = true;
mListener.onCancelled(mReadyDispatched ? this : null);
@@ -488,15 +489,15 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro
return;
}
- final boolean visible = mPendingFraction == 0
- // The first frame of ANIMATION_TYPE_SHOW should be invisible since it is
- // animated from the hidden state.
- ? mAnimationType != ANIMATION_TYPE_SHOW
- : mPendingFraction < 1f || (mFinished
- ? mShownOnFinish
- // If the animation is cancelled, mFinished and mShownOnFinish are not set.
+ final boolean visible = mFinished
+ ? mShownOnFinish
+ : (mCancelling
+ // If the animation is being cancelled, mShownOnFinish is not valid.
// Here uses mLayoutInsetsDuringAnimation to decide if it should be visible.
- : mLayoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN);
+ ? mLayoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN
+ // The first frame of ANIMATION_TYPE_SHOW should be invisible since it is
+ // animated from the hidden state.
+ : (mAnimationType != ANIMATION_TYPE_SHOW || mPendingFraction != 0));
// TODO: Implement behavior when inset spans over multiple types
for (int i = controls.size() - 1; i >= 0; i--) {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index e665c08c63e4..d7cf3e827695 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -4865,7 +4865,7 @@ public final class SurfaceControl implements Parcelable {
/**
* @hide
*/
- public Transaction setDesintationFrame(SurfaceControl sc, @NonNull Rect destinationFrame) {
+ public Transaction setDestinationFrame(SurfaceControl sc, @NonNull Rect destinationFrame) {
checkPreconditions(sc);
nativeSetDestinationFrame(mNativeObject, sc.mNativeObject,
destinationFrame.left, destinationFrame.top, destinationFrame.right,
@@ -4876,7 +4876,7 @@ public final class SurfaceControl implements Parcelable {
/**
* @hide
*/
- public Transaction setDesintationFrame(SurfaceControl sc, int width, int height) {
+ public Transaction setDestinationFrame(SurfaceControl sc, int width, int height) {
checkPreconditions(sc);
nativeSetDestinationFrame(mNativeObject, sc.mNativeObject, 0, 0, width, height);
return this;
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index b0051cefb21b..780e76122e8a 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1125,7 +1125,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
}
- surfaceUpdateTransaction.setDesintationFrame(mBlastSurfaceControl, mSurfaceWidth,
+ surfaceUpdateTransaction.setDestinationFrame(mBlastSurfaceControl, mSurfaceWidth,
mSurfaceHeight);
if (isHardwareAccelerated()) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 36671b901a6b..0972c01aa653 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -134,7 +134,6 @@ import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme;
import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay;
import static com.android.window.flags.Flags.predictiveBackSwipeEdgeNoneApi;
import static com.android.window.flags.Flags.setScPropertiesInClient;
-import static com.android.window.flags.Flags.systemUiImmersiveConfirmationDialog;
import android.Manifest;
import android.accessibilityservice.AccessibilityService;
@@ -377,16 +376,6 @@ public final class ViewRootImpl implements ViewParent,
SystemProperties.getBoolean("persist.wm.debug.client_transient", false);
/**
- * Whether the client (system UI) is handling the immersive confirmation window. If
- * {@link CLIENT_TRANSIENT} is set to true, the immersive confirmation window will always be the
- * client instance and this flag will be ignored. Otherwise, the immersive confirmation window
- * can be switched freely by this flag.
- * @hide
- */
- public static final boolean CLIENT_IMMERSIVE_CONFIRMATION =
- systemUiImmersiveConfirmationDialog();
-
- /**
* Set this system property to true to force the view hierarchy to render
* at 60 Hz. This can be used to measure the potential framerate.
*/
@@ -2770,14 +2759,15 @@ public final class ViewRootImpl implements ViewParent,
if (mBlastBufferQueue != null) {
mBlastBufferQueue.destroy();
}
- mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
- mSurfaceSize.x, mSurfaceSize.y, mWindowAttributes.format);
- mBlastBufferQueue.setTransactionHangCallback(sTransactionHangCallback);
- mBlastBufferQueue.setWaitForBufferReleaseCallback(mChoreographer::onWaitForBufferRelease);
+ mBlastBufferQueue = new BLASTBufferQueue(mTag, true /* updateDestinationFrame */);
// If we create and destroy BBQ without recreating the SurfaceControl, we can end up
// queuing buffers on multiple apply tokens causing out of order buffer submissions. We
// fix this by setting the same apply token on all BBQs created by this VRI.
mBlastBufferQueue.setApplyToken(mBbqApplyToken);
+ mBlastBufferQueue.update(mSurfaceControl, mSurfaceSize.x, mSurfaceSize.y,
+ mWindowAttributes.format);
+ mBlastBufferQueue.setTransactionHangCallback(sTransactionHangCallback);
+ mBlastBufferQueue.setWaitForBufferReleaseCallback(mChoreographer::onWaitForBufferRelease);
Surface blastSurface;
if (addSchandleToVriSurface()) {
blastSurface = mBlastBufferQueue.createSurfaceWithHandle();
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 25bd713d9191..a5da0c3ce5b1 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -50,6 +50,7 @@ import android.window.TrustedPresentationThresholds;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.policy.PhoneWindow;
import com.android.internal.util.FastPrintWriter;
import java.io.FileDescriptor;
@@ -375,7 +376,8 @@ public final class WindowManagerGlobal {
if (context != null && wparams.type > LAST_APPLICATION_WINDOW) {
final TypedArray styles = context.obtainStyledAttributes(R.styleable.Window);
- if (styles.getBoolean(R.styleable.Window_windowOptOutEdgeToEdgeEnforcement, false)) {
+ if (PhoneWindow.isOptingOutEdgeToEdgeEnforcement(
+ context.getApplicationInfo(), true /* local */, styles)) {
wparams.privateFlags |= PRIVATE_FLAG_OPT_OUT_EDGE_TO_EDGE;
}
styles.recycle();
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 33890b80869d..f70bf9737636 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -1021,8 +1021,9 @@ public final class Magnifier {
.setCallsite("InternalPopupWindow")
.build();
- mBBQ = new BLASTBufferQueue("magnifier surface", mBbqSurfaceControl,
- surfaceWidth, surfaceHeight, PixelFormat.TRANSLUCENT);
+ mBBQ = new BLASTBufferQueue("magnifier surface", /*updateDestinationFrame*/ true);
+ mBBQ.update(mBbqSurfaceControl,
+ surfaceWidth, surfaceHeight, PixelFormat.TRANSLUCENT);
mSurface = mBBQ.createSurface();
// Setup the RenderNode tree. The root has two children, one containing the bitmap
diff --git a/core/java/android/window/TaskFragmentOperation.java b/core/java/android/window/TaskFragmentOperation.java
index 6f7660a0fb3d..9d0ea547e734 100644
--- a/core/java/android/window/TaskFragmentOperation.java
+++ b/core/java/android/window/TaskFragmentOperation.java
@@ -161,6 +161,16 @@ public final class TaskFragmentOperation implements Parcelable {
*/
public static final int OP_TYPE_SET_PINNED = 19;
+ /**
+ * Sets whether this TaskFragment can affect system UI flags such as the status bar. Default
+ * is {@code true}.
+ *
+ * This operation is only allowed for system organizers. See
+ * {@link com.android.server.wm.TaskFragmentOrganizerController#registerOrganizer(
+ * ITaskFragmentOrganizer, boolean)}
+ */
+ public static final int OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS = 20;
+
@IntDef(prefix = { "OP_TYPE_" }, value = {
OP_TYPE_UNKNOWN,
OP_TYPE_CREATE_TASK_FRAGMENT,
@@ -183,6 +193,7 @@ public final class TaskFragmentOperation implements Parcelable {
OP_TYPE_SET_MOVE_TO_BOTTOM_IF_CLEAR_WHEN_LAUNCH,
OP_TYPE_SET_DECOR_SURFACE_BOOSTED,
OP_TYPE_SET_PINNED,
+ OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface OperationType {}
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 2c21417fb790..ddbf9e49bb8d 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -211,7 +211,7 @@ public final class TransitionInfo implements Parcelable {
FLAG_CONFIG_AT_END,
FLAG_IS_TASK_DISPLAY_AREA,
FLAG_FIRST_CUSTOM
- }, flag = true)
+ })
public @interface ChangeFlags {}
private final @TransitionType int mType;
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index be0b4fea459c..b4e7675402b9 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -463,6 +463,13 @@ flag {
}
flag {
+ name: "enable_connected_displays_pip"
+ namespace: "lse_desktop_experience"
+ description: "Enables PiP features in connected displays."
+ bug: "362721131"
+}
+
+flag {
name: "reparent_window_token_api"
namespace: "lse_desktop_experience"
description: "Allows to reparent a window token to a different display"
@@ -531,6 +538,16 @@ flag {
}
flag {
+ name: "enable_per_display_package_context_cache_in_statusbar_notif"
+ namespace: "lse_desktop_experience"
+ description: "Enables per-display package context caching in StatusBarNotification"
+ bug: "388886443"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "enable_desktop_wallpaper_activity_for_system_user"
namespace: "lse_desktop_experience"
description: "Enables starting DesktopWallpaperActivity on system user."
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 7a1078f8718f..c2e305d72dd0 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -257,14 +257,6 @@ flag {
}
flag {
- name: "system_ui_immersive_confirmation_dialog"
- namespace: "windowing_frontend"
- description: "Enable the implementation of the immersive confirmation dialog on system UI side by default"
- bug: "359713629"
- is_fixed_read_only: true
-}
-
-flag {
name: "ensure_wallpaper_in_transitions"
namespace: "windowing_frontend"
description: "Ensure that wallpaper window tokens are always present/available for collection in transitions"
@@ -426,9 +418,36 @@ flag {
}
flag {
+ name: "use_rt_frame_callback_for_splash_screen_transfer"
+ namespace: "windowing_frontend"
+ description: "report SplashscreenView shown after RtFrame commit"
+ is_fixed_read_only: true
+ bug: "387231234"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "port_window_size_animation"
namespace: "windowing_frontend"
description: "Port window-resize animation from legacy to shell"
bug: "384976265"
}
+flag {
+ name: "aod_transition"
+ namespace: "windowing_frontend"
+ description: "Support to show lock wallpaper in aod state"
+ bug: "361438779"
+}
+
+flag {
+ name: "check_disabled_snapshots_in_task_persister"
+ namespace: "windowing_frontend"
+ description: "Check for TaskSnapshots disabling in TaskSnapshotPersister."
+ bug: "387915176"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+} \ No newline at end of file
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
index cf3a54b8437f..b187eb42366f 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
@@ -181,7 +181,8 @@ public final class AccessibilityTargetHelper {
final InvisibleToggleAllowListingFeatureTarget magnification =
new InvisibleToggleAllowListingFeatureTarget(context,
shortcutType,
- isShortcutContained(context, shortcutType, MAGNIFICATION_CONTROLLER_NAME),
+ isShortcutContained(
+ context, shortcutType, MAGNIFICATION_CONTROLLER_NAME),
MAGNIFICATION_CONTROLLER_NAME,
uid,
context.getString(R.string.accessibility_magnification_chooser_text),
diff --git a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
index 14ca0f8cae69..fc3c48d19b68 100644
--- a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
+++ b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
@@ -25,6 +25,7 @@ import static com.android.internal.accessibility.AccessibilityShortcutController
import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType.INVISIBLE_TOGGLE;
import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR;
import static com.android.internal.accessibility.common.ShortcutConstants.USER_SHORTCUT_TYPES;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.DEFAULT;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.KEY_GESTURE;
@@ -157,19 +158,42 @@ public final class ShortcutUtils {
}
/**
- * Returns if a {@code shortcutType} shortcut contains {@code componentId}.
+ * Returns if a {@code shortcutType} shortcut contains {@code componentName}.
*
* @param context The current context.
* @param shortcutType The preferred shortcut type user selected.
- * @param componentId The component id that need to be checked.
- * @return {@code true} if a component id is contained.
+ * @param componentName The component that need to be checked.
+ * @return {@code true} if the shortcut contains {@code componentName}.
*/
- public static boolean isShortcutContained(Context context, @UserShortcutType int shortcutType,
- @NonNull String componentId) {
- final AccessibilityManager am = (AccessibilityManager) context.getSystemService(
- Context.ACCESSIBILITY_SERVICE);
- final List<String> requiredTargets = am.getAccessibilityShortcutTargets(shortcutType);
- return requiredTargets.contains(componentId);
+ @SuppressLint("MissingPermission")
+ public static boolean isShortcutContained(
+ Context context, @UserShortcutType int shortcutType, @NonNull String componentName) {
+ AccessibilityManager manager = context.getSystemService(AccessibilityManager.class);
+ if (manager != null) {
+ return manager
+ .getAccessibilityShortcutTargets(shortcutType).contains(componentName);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns every shortcut type that currently has the provided componentName as a target.
+ * Types are returned as a singular flag integer.
+ * If none have the componentName, returns {@link UserShortcutType#DEFAULT}
+ */
+ public static int getEnabledShortcutTypes(
+ Context context, String componentName) {
+ final AccessibilityManager am = context.getSystemService(AccessibilityManager.class);
+ if (am == null) return DEFAULT;
+
+ int shortcutTypes = DEFAULT;
+ for (int shortcutType : USER_SHORTCUT_TYPES) {
+ if (am.getAccessibilityShortcutTargets(shortcutType).contains(componentName)) {
+ shortcutTypes |= shortcutType;
+ }
+ }
+ return shortcutTypes;
}
/**
@@ -229,8 +253,7 @@ public final class ShortcutUtils {
*/
public static void updateInvisibleToggleAccessibilityServiceEnableState(
Context context, Set<String> componentNames, int userId) {
- final AccessibilityManager am = (AccessibilityManager) context.getSystemService(
- Context.ACCESSIBILITY_SERVICE);
+ final AccessibilityManager am = context.getSystemService(AccessibilityManager.class);
if (am == null) return;
final List<AccessibilityServiceInfo> installedServices =
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 644d69919998..9d7bedc4d0c3 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -689,14 +689,15 @@ public class IntentForwarderActivity extends Activity {
}
private void setMiniresolverPadding() {
- Insets systemWindowInsets =
- getWindowManager().getCurrentWindowMetrics().getWindowInsets().getInsets(
- WindowInsets.Type.systemBars());
-
View buttonContainer = findViewById(R.id.button_bar_container);
- buttonContainer.setPadding(0, 0, 0,
- systemWindowInsets.bottom + getResources().getDimensionPixelOffset(
- R.dimen.resolver_button_bar_spacing));
+ if (buttonContainer != null) {
+ Insets systemWindowInsets =
+ getWindowManager().getCurrentWindowMetrics().getWindowInsets().getInsets(
+ WindowInsets.Type.systemBars());
+ buttonContainer.setPadding(0, 0, 0,
+ systemWindowInsets.bottom + getResources().getDimensionPixelOffset(
+ R.dimen.resolver_button_bar_spacing));
+ }
}
@VisibleForTesting
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index a1945352ae09..db65d31f59da 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -929,8 +929,11 @@ public class ResolverActivity extends Activity implements
if (shouldUseMiniResolver()) {
View buttonContainer = findViewById(R.id.button_bar_container);
- buttonContainer.setPadding(0, 0, 0, mSystemWindowInsets.bottom
- + getResources().getDimensionPixelOffset(R.dimen.resolver_button_bar_spacing));
+ if (buttonContainer != null) {
+ buttonContainer.setPadding(0, 0, 0, mSystemWindowInsets.bottom
+ + getResources().getDimensionPixelOffset(
+ R.dimen.resolver_button_bar_spacing));
+ }
}
// Need extra padding so the list can fully scroll up
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 6ad7fef95357..e170d6652863 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -172,8 +172,7 @@ public class NativeLibraryHelper {
private static native long nativeOpenApkFd(FileDescriptor fd, String debugPath);
private static native void nativeClose(long handle);
- private static native long nativeSumNativeBinaries(long handle, String cpuAbi,
- boolean debuggable);
+ private static native long nativeSumNativeBinaries(long handle, String cpuAbi);
private native static int nativeCopyNativeBinaries(long handle, String sharedLibraryPath,
String abiToCopy, boolean extractNativeLibs, boolean debuggable);
@@ -188,7 +187,7 @@ public class NativeLibraryHelper {
private static long sumNativeBinaries(Handle handle, String abi) {
long sum = 0;
for (long apkHandle : handle.apkHandles) {
- sum += nativeSumNativeBinaries(apkHandle, abi, handle.debuggable);
+ sum += nativeSumNativeBinaries(apkHandle, abi);
}
return sum;
}
@@ -222,7 +221,7 @@ public class NativeLibraryHelper {
public static int findSupportedAbi(Handle handle, String[] supportedAbis) {
int finalRes = NO_NATIVE_LIBRARIES;
for (long apkHandle : handle.apkHandles) {
- final int res = nativeFindSupportedAbi(apkHandle, supportedAbis, handle.debuggable);
+ final int res = nativeFindSupportedAbi(apkHandle, supportedAbis);
if (res == NO_NATIVE_LIBRARIES) {
// No native code, keep looking through all APKs.
} else if (res == INSTALL_FAILED_NO_MATCHING_ABIS) {
@@ -244,8 +243,7 @@ public class NativeLibraryHelper {
return finalRes;
}
- private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis,
- boolean debuggable);
+ private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis);
// Convenience method to call removeNativeBinariesFromDirLI(File)
public static void removeNativeBinariesLI(String nativeLibraryPath) {
diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java
index d1adfc95461d..158b526cb1a0 100644
--- a/core/java/com/android/internal/jank/Cuj.java
+++ b/core/java/com/android/internal/jank/Cuj.java
@@ -257,8 +257,16 @@ public class Cuj {
*/
public static final int CUJ_DESKTOP_MODE_ENTER_FROM_OVERVIEW_MENU = 120;
+ /** Track Launcher Overview Task Dismiss animation.
+ *
+ * <p>Tracking starts when the overview task is dismissed via
+ * {@link com.android.quickstep.views.RecentsView#dismissTask}. Tracking finishes when the
+ * animation to dismiss the overview task ends.
+ */
+ public static final int CUJ_LAUNCHER_OVERVIEW_TASK_DISMISS = 121;
+
// When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE.
- @VisibleForTesting static final int LAST_CUJ = CUJ_DESKTOP_MODE_ENTER_FROM_OVERVIEW_MENU;
+ @VisibleForTesting static final int LAST_CUJ = CUJ_LAUNCHER_OVERVIEW_TASK_DISMISS;
/** @hide */
@IntDef({
@@ -370,7 +378,8 @@ public class Cuj {
CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE,
CUJ_DESKTOP_MODE_SNAP_RESIZE,
CUJ_DESKTOP_MODE_UNMAXIMIZE_WINDOW,
- CUJ_DESKTOP_MODE_ENTER_FROM_OVERVIEW_MENU
+ CUJ_DESKTOP_MODE_ENTER_FROM_OVERVIEW_MENU,
+ CUJ_LAUNCHER_OVERVIEW_TASK_DISMISS
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {}
@@ -493,6 +502,7 @@ public class Cuj {
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_SNAP_RESIZE] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_SNAP_RESIZE;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_UNMAXIMIZE_WINDOW] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_UNMAXIMIZE_WINDOW;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_ENTER_FROM_OVERVIEW_MENU] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_ENTER_FROM_OVERVIEW_MENU;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_OVERVIEW_TASK_DISMISS] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_OVERVIEW_TASK_DISMISS;
}
private Cuj() {
@@ -729,6 +739,8 @@ public class Cuj {
return "DESKTOP_MODE_UNMAXIMIZE_WINDOW";
case CUJ_DESKTOP_MODE_ENTER_FROM_OVERVIEW_MENU:
return "DESKTOP_MODE_ENTER_FROM_OVERVIEW_MENU";
+ case CUJ_LAUNCHER_OVERVIEW_TASK_DISMISS:
+ return "LAUNCHER_OVERVIEW_TASK_DISMISS";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 1709ca78af4b..f6de3459a1f5 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -174,7 +174,9 @@ public class RuntimeInit {
// System process is dead; ignore
} else {
try {
- Clog_e(TAG, "Error reporting crash", t2);
+ // Log original crash and then log the error reporting exception.
+ Clog_e(TAG, "Couldn't report crash. Here's the crash:", e);
+ Clog_e(TAG, "Error reporting crash. Here's the error:", t2);
} catch (Throwable t3) {
// Even Clog_e() fails! Oh well.
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index e0529b339d4a..6c00921ebb7b 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -184,6 +184,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private static final long ENFORCE_EDGE_TO_EDGE = 309578419;
/**
+ * Disable opting out the edge-to-edge enforcement.
+ * {@link Build.VERSION_CODES#BAKLAVA} or above.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.BAKLAVA)
+ private static final long DISABLE_OPT_OUT_EDGE_TO_EDGE = 377864165;
+
+ /**
* Override the layout in display cutout mode behavior. This will only apply if the edge to edge
* is not enforced.
*/
@@ -450,7 +458,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
*/
public static boolean isEdgeToEdgeEnforced(ApplicationInfo info, boolean local,
TypedArray windowStyle) {
- return !windowStyle.getBoolean(R.styleable.Window_windowOptOutEdgeToEdgeEnforcement, false)
+ return !isOptingOutEdgeToEdgeEnforcement(info, local, windowStyle)
&& (info.targetSdkVersion >= ENFORCE_EDGE_TO_EDGE_SDK_VERSION
|| (Flags.enforceEdgeToEdge() && (local
// Calling this doesn't require a permission.
@@ -459,6 +467,29 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
: info.isChangeEnabled(ENFORCE_EDGE_TO_EDGE))));
}
+ /**
+ * Returns whether the given application is opting out edge-to-edge enforcement.
+ *
+ * @param info The application to query.
+ * @param local Whether this is called from the process of the given application.
+ * @param windowStyle The style of the window.
+ * @return {@code true} if the edge-to-edge enforcement is opting out. Otherwise, {@code false}.
+ */
+ public static boolean isOptingOutEdgeToEdgeEnforcement(ApplicationInfo info, boolean local,
+ TypedArray windowStyle) {
+ final boolean disabled = Flags.disableOptOutEdgeToEdge()
+ // TODO (b/377864165): Don't exclude system apps after they are ready.
+ && !info.isSystemApp()
+ && (local
+ // Calling this doesn't require a permission.
+ ? CompatChanges.isChangeEnabled(DISABLE_OPT_OUT_EDGE_TO_EDGE)
+ // Calling this requires permissions.
+ : info.isChangeEnabled(DISABLE_OPT_OUT_EDGE_TO_EDGE));
+ return !disabled && windowStyle.getBoolean(
+ R.styleable.Window_windowOptOutEdgeToEdgeEnforcement, false /* default */);
+
+ }
+
@Override
public final void setContainer(Window container) {
super.setContainer(container);
@@ -2486,6 +2517,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
TypedArray a = getWindowStyle();
WindowManager.LayoutParams params = getAttributes();
+ ApplicationInfo appInfo = getContext().getApplicationInfo();
if (false) {
System.out.println("From style:");
@@ -2497,8 +2529,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
System.out.println(s);
}
- mEdgeToEdgeEnforced = isEdgeToEdgeEnforced(
- getContext().getApplicationInfo(), true /* local */, a);
+ mEdgeToEdgeEnforced = isEdgeToEdgeEnforced(appInfo, true /* local */, a);
if (mEdgeToEdgeEnforced) {
getAttributes().privateFlags |= PRIVATE_FLAG_EDGE_TO_EDGE_ENFORCED;
mDecorFitsSystemWindows = false;
@@ -2507,8 +2538,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// mNavigationBarColor is not reset here because it might be used to draw the scrim.
}
if (CompatChanges.isChangeEnabled(OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE)
- && !a.getBoolean(R.styleable.Window_windowOptOutEdgeToEdgeEnforcement,
- false /* defValue */)) {
+ && !isOptingOutEdgeToEdgeEnforcement(appInfo, true /* local */, a)) {
getAttributes().privateFlags |= PRIVATE_FLAG_OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE;
}
diff --git a/core/java/com/android/internal/widget/NotificationProgressBar.java b/core/java/com/android/internal/widget/NotificationProgressBar.java
index 904b73f41e70..0d3c470b0e8a 100644
--- a/core/java/com/android/internal/widget/NotificationProgressBar.java
+++ b/core/java/com/android/internal/widget/NotificationProgressBar.java
@@ -817,12 +817,13 @@ public final class NotificationProgressBar extends ProgressBar implements
if (part instanceof Segment segment) {
final float segWidth = segment.mFraction * totalWidth;
// Advance the start position to account for a point immediately prior.
- final float startOffset = getSegStartOffset(prevPart, pointRadius, segPointGap, x);
+ final float startOffset = getSegStartOffset(prevPart, pointRadius, segPointGap,
+ iPart == 1);
final float start = x + startOffset;
// Retract the end position to account for the padding and a point immediately
// after.
final float endOffset = getSegEndOffset(segment, nextPart, pointRadius, segPointGap,
- segSegGap, x + segWidth, totalWidth, hasTrackerIcon);
+ segSegGap, iPart == nParts - 2, totalWidth, hasTrackerIcon);
final float end = x + segWidth - endOffset;
drawableParts.add(new DrawableSegment(start, end, segment.mColor, segment.mFaded));
@@ -836,11 +837,16 @@ public final class NotificationProgressBar extends ProgressBar implements
} else if (part instanceof Point point) {
final float pointWidth = 2 * pointRadius;
float start = x - pointRadius;
- if (start < 0) start = 0;
- float end = start + pointWidth;
- if (end > totalWidth) {
+ float end = x + pointRadius;
+ // Only shift the points right at the start/end.
+ // For the points close to the start/end, the segment minimum width requirement
+ // would take care of shifting them to be within the bounds.
+ if (iPart == 0) {
+ start = 0;
+ end = pointWidth;
+ } else if (iPart == nParts - 1) {
+ start = totalWidth - pointWidth;
end = totalWidth;
- if (totalWidth > pointWidth) start = totalWidth - pointWidth;
}
drawableParts.add(new DrawablePoint(start, end, point.mColor));
@@ -851,14 +857,14 @@ public final class NotificationProgressBar extends ProgressBar implements
}
private static float getSegStartOffset(Part prevPart, float pointRadius, float segPointGap,
- float startX) {
+ boolean isSecondPart) {
if (!(prevPart instanceof Point)) return 0F;
- final float pointOffset = (startX < pointRadius) ? (pointRadius - startX) : 0;
+ final float pointOffset = isSecondPart ? pointRadius : 0;
return pointOffset + pointRadius + segPointGap;
}
private static float getSegEndOffset(Segment seg, Part nextPart, float pointRadius,
- float segPointGap, float segSegGap, float endX, float totalWidth,
+ float segPointGap, float segSegGap, boolean isSecondToLastPart, float totalWidth,
boolean hasTrackerIcon) {
if (nextPart == null) return 0F;
if (nextPart instanceof Segment nextSeg) {
@@ -869,9 +875,7 @@ public final class NotificationProgressBar extends ProgressBar implements
return segSegGap;
}
- final float pointWidth = 2 * pointRadius;
- final float pointOffset = (endX + pointRadius > totalWidth && totalWidth > pointWidth)
- ? (endX + pointRadius - totalWidth) : 0;
+ final float pointOffset = isSecondToLastPart ? pointRadius : 0;
return segPointGap + pointRadius + pointOffset;
}
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index 3108f1f2c7c5..e78c5247d8a7 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -349,21 +349,19 @@ static install_status_t copyFileIfChanged(JNIEnv* env, void* arg, ZipFileRO* zip
* satisfied :
*
* - The entry is under the lib/ directory.
- * - The entry name ends with ".so" and the entry name starts with "lib",
- * an exception is made for debuggable apps.
* - The entry filename is "safe" (as determined by isFilenameSafe).
*
*/
class NativeLibrariesIterator {
private:
- NativeLibrariesIterator(ZipFileRO* zipFile, bool debuggable, void* cookie)
- : mZipFile(zipFile), mDebuggable(debuggable), mCookie(cookie), mLastSlash(nullptr) {
+ NativeLibrariesIterator(ZipFileRO* zipFile, void* cookie)
+ : mZipFile(zipFile), mCookie(cookie), mLastSlash(nullptr) {
fileName[0] = '\0';
}
public:
static base::expected<std::unique_ptr<NativeLibrariesIterator>, int32_t> create(
- ZipFileRO* zipFile, bool debuggable) {
+ ZipFileRO* zipFile) {
// Do not specify a suffix to find both .so files and gdbserver.
auto result = zipFile->startIterationOrError(APK_LIB.data(), nullptr /* suffix */);
if (!result.ok()) {
@@ -371,7 +369,7 @@ public:
}
return std::unique_ptr<NativeLibrariesIterator>(
- new NativeLibrariesIterator(zipFile, debuggable, result.value()));
+ new NativeLibrariesIterator(zipFile, result.value()));
}
base::expected<ZipEntryRO, int32_t> next() {
@@ -390,7 +388,7 @@ public:
continue;
}
- const char* lastSlash = util::ValidLibraryPathLastSlash(fileName, false, mDebuggable);
+ const char* lastSlash = util::ValidLibraryPathLastSlash(fileName, false);
if (lastSlash) {
mLastSlash = lastSlash;
break;
@@ -415,20 +413,19 @@ private:
char fileName[PATH_MAX];
ZipFileRO* const mZipFile;
- const bool mDebuggable;
void* mCookie;
const char* mLastSlash;
};
static install_status_t
iterateOverNativeFiles(JNIEnv *env, jlong apkHandle, jstring javaCpuAbi,
- jboolean debuggable, iterFunc callFunc, void* callArg) {
+ iterFunc callFunc, void* callArg) {
ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle);
if (zipFile == nullptr) {
return INSTALL_FAILED_INVALID_APK;
}
- auto result = NativeLibrariesIterator::create(zipFile, debuggable);
+ auto result = NativeLibrariesIterator::create(zipFile);
if (!result.ok()) {
return INSTALL_FAILED_INVALID_APK;
}
@@ -470,14 +467,13 @@ iterateOverNativeFiles(JNIEnv *env, jlong apkHandle, jstring javaCpuAbi,
return INSTALL_SUCCEEDED;
}
-static int findSupportedAbi(JNIEnv* env, jlong apkHandle, jobjectArray supportedAbisArray,
- jboolean debuggable) {
+static int findSupportedAbi(JNIEnv* env, jlong apkHandle, jobjectArray supportedAbisArray) {
ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle);
if (zipFile == nullptr) {
return INSTALL_FAILED_INVALID_APK;
}
- auto result = NativeLibrariesIterator::create(zipFile, debuggable);
+ auto result = NativeLibrariesIterator::create(zipFile);
if (!result.ok()) {
return INSTALL_FAILED_INVALID_APK;
}
@@ -548,26 +544,26 @@ com_android_internal_content_NativeLibraryHelper_copyNativeBinaries(JNIEnv *env,
{
jboolean app_compat_16kb = app_compat_16kb_enabled();
void* args[] = { &javaNativeLibPath, &extractNativeLibs, &debuggable, &app_compat_16kb };
- return (jint) iterateOverNativeFiles(env, apkHandle, javaCpuAbi, debuggable,
+ return (jint) iterateOverNativeFiles(env, apkHandle, javaCpuAbi,
copyFileIfChanged, reinterpret_cast<void*>(args));
}
static jlong
com_android_internal_content_NativeLibraryHelper_sumNativeBinaries(JNIEnv *env, jclass clazz,
- jlong apkHandle, jstring javaCpuAbi, jboolean debuggable)
+ jlong apkHandle, jstring javaCpuAbi)
{
size_t totalSize = 0;
- iterateOverNativeFiles(env, apkHandle, javaCpuAbi, debuggable, sumFiles, &totalSize);
+ iterateOverNativeFiles(env, apkHandle, javaCpuAbi, sumFiles, &totalSize);
return totalSize;
}
static jint
com_android_internal_content_NativeLibraryHelper_findSupportedAbi(JNIEnv *env, jclass clazz,
- jlong apkHandle, jobjectArray javaCpuAbisToSearch, jboolean debuggable)
+ jlong apkHandle, jobjectArray javaCpuAbisToSearch)
{
- return (jint) findSupportedAbi(env, apkHandle, javaCpuAbisToSearch, debuggable);
+ return (jint) findSupportedAbi(env, apkHandle, javaCpuAbisToSearch);
}
enum bitcode_scan_result_t {
@@ -748,7 +744,7 @@ static jint com_android_internal_content_NativeLibraryHelper_checkApkAlignment(
return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
}
- auto result = NativeLibrariesIterator::create(zipFile, debuggable);
+ auto result = NativeLibrariesIterator::create(zipFile);
if (!result.ok()) {
ALOGE("Can't iterate over native libs for file:%s", zipFile->getZipFileName());
return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
@@ -810,9 +806,9 @@ static const JNINativeMethod gMethods[] = {
{"nativeClose", "(J)V", (void*)com_android_internal_content_NativeLibraryHelper_close},
{"nativeCopyNativeBinaries", "(JLjava/lang/String;Ljava/lang/String;ZZ)I",
(void*)com_android_internal_content_NativeLibraryHelper_copyNativeBinaries},
- {"nativeSumNativeBinaries", "(JLjava/lang/String;Z)J",
+ {"nativeSumNativeBinaries", "(JLjava/lang/String;)J",
(void*)com_android_internal_content_NativeLibraryHelper_sumNativeBinaries},
- {"nativeFindSupportedAbi", "(J[Ljava/lang/String;Z)I",
+ {"nativeFindSupportedAbi", "(J[Ljava/lang/String;)I",
(void*)com_android_internal_content_NativeLibraryHelper_findSupportedAbi},
{"hasRenderscriptBitcode", "(J)I",
(void*)com_android_internal_content_NativeLibraryHelper_hasRenderscriptBitcode},
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 0eb7c4aee287..5225ce878310 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -51,7 +51,8 @@ static const char* kPathAllowlist[] = {
"/dev/blkio/tasks",
"/metadata/aconfig/maps/system.package.map",
"/metadata/aconfig/maps/system.flag.map",
- "/metadata/aconfig/boot/system.val"
+ "/metadata/aconfig/boot/system.val",
+ "/metadata/libprocessgroup/memcg_v2_max_activation_depth" // TODO Revert after go/android-memcgv2-exp b/386797433
};
static const char kFdPath[] = "/proc/self/fd";
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ed021b64f7a0..73279700ecb1 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -180,6 +180,7 @@
<protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL" />
<protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST" />
<protected-broadcast android:name="android.bluetooth.device.action.KEY_MISSING" />
+ <protected-broadcast android:name="android.bluetooth.device.action.ENCRYPTION_CHANGE" />
<protected-broadcast android:name="android.bluetooth.device.action.SDP_RECORD" />
<protected-broadcast android:name="android.bluetooth.device.action.BATTERY_LEVEL_CHANGED" />
<protected-broadcast android:name="android.bluetooth.device.action.REMOTE_ISSUE_OCCURRED" />
@@ -8804,22 +8805,6 @@
<permission android:name="android.permission.RESERVED_FOR_TESTING_SIGNATURE"
android:protectionLevel="signature"/>
- <!--
- This permission allows the system to receive PACKAGE_CHANGED broadcasts when the component
- state of a non-exported component has been changed.
- <p>Not for use by third-party applications. </p>
- <p>Protection level: internal
- @hide
- -->
- <permission
- android:name="android.permission.INTERNAL_RECEIVE_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED"
- android:protectionLevel="internal"
- android:featureFlag="android.content.pm.reduce_broadcasts_for_component_state_changes"/>
-
- <uses-permission
- android:name="android.permission.INTERNAL_RECEIVE_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED"
- android:featureFlag="android.content.pm.reduce_broadcasts_for_component_state_changes"/>
-
<!-- @SystemApi
@FlaggedApi("android.media.tv.flags.kids_mode_tvdb_sharing")
This permission is required when accessing information related to
@@ -9272,6 +9257,11 @@
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
+ <service android:name="com.android.server.ZramMaintenance"
+ android:exported="false"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
<service android:name="com.android.server.ZramWriteback"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE" >
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 1578bc23dfe8..59414771c36c 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Kan nie selnetwerk bereik nie"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Probeer die voorkeurnetwerk verander. Tik om te verander."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Noodoproepe is onbeskikbaar"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Moenie weer wys nie"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Noodoproepe vereis ’n selnetwerk."</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Opletberigte"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Oproepaanstuur"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Netwerkwaarskuwings"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Netwerk is beskikbaar"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN-status"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Tyd en tydsones"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Opletberigte van jou IT-admin af"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Opletberigte"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Kleinhandeldemonstrasie"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"App loop tans"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Programme wat batterykrag gebruik"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Vergroting"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Gehoortoestel"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Toeganklikheidgebruik"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Skerm"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> gebruik tans batterykrag"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Laai app af"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Nuwe SIM is ingesit"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Tik om dit op te stel"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Jou tydsone het verander"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Jy is nou in <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Stel tyd"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Stel datum"</string>
<string name="date_time_set" msgid="4603445265164486816">"Stel"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Eenhandmodus"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra donker"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Gehoortoestelle"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Ontkoppel"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Gekoppel"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktief"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Laai tans"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Het volumesleutels ingehou. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aangeskakel."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Het volumesleutels ingehou. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> is afgeskakel"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Los die volumesleutels. Druk en hou albei volumesleutels weer 3 sekondes lank in om <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aan te skakel."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Skakel oor na foonmikrofoon?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Skakel oor na gehoortoestelmikrofoon?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Vir beter klank of as jou gehoortoestel se battery laag is. Dit skakel net jou mikrofoon tydens die oproep oor."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Jy kan jou gehoortoestel en mikrofoon vir handvrye oproepe gebruik. Dit skakel net jou mikrofoon tydens die oproep oor."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Skakel oor"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Instellings"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Meld <xliff:g id="NAME">%1$s</xliff:g> tans af …"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Appinhoud is weens sekuriteit van skermdeling verberg"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Outomaties aan satelliet gekoppel"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Jy kan boodskappe stuur en ontvang sonder ’n selfoon- of wi-fi-netwerk"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Gebruik satellietboodskappe?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Stuur en ontvang boodskappe sonder ’n selfoon- of wi-fi-netwerk"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Maak Boodskappe oop"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 114013007fbe..0ca5ab4a338d 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"የሞባይል አውታረ መረብን መድረስ አልተቻለም"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ተመራጭ አውታረ መረብን ለመለወጥ ይሞክሩ። ለመለወጥ መታ ያድርጉ።"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"የአደጋ ጊዜ ጥሪ አይገኝም"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"ዳግም አታሳይ"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"የአደጋ ጥሪዎች የተንቀሳቃሽ ስልክ አውታረ መረብ ያስፈልጋቸዋል"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"ማንቂያዎች"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ጥሪ ማስተላለፍ"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"የአውታረ መረብ ማንቂያዎች"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"አውታረ መረብ ይገኛል"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"የቪፒኤን ሁኔታ"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"ጊዜ እና የሰዓት ሰቆች"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"ከእርስዎ አይቲ አስተዳዳሪ የመጡ ማንቂያዎች"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"ማንቂያዎች"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"የችርቻሮ ማሳያ"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"APP እየሠራ ነው"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"ባትሪ በመፍጀት ላይ ያሉ መተግበሪያዎች"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"ማጉላት"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"የመስማት ችሎታ መሣሪያ"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"የተደራሽነት አጠቃቀም"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"ማሳያ"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> ባትሪ እየተጠቀመ ነው"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"መተግበሪያን አውርድ"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"አዲስ ሲም ገብቷል"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"ለማዋቀር መታ ያድርጉ"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"የእርስዎ የሰዓት ሰቅ ተለውጧል"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"አሁን <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) ውስጥ ነዎት"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"ጊዜ አዘጋጅ"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"ውሂብ አዘጋጅ"</string>
<string name="date_time_set" msgid="4603445265164486816">"አዘጋጅ"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"የአንድ እጅ ሁነታ"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ተጨማሪ ደብዛዛ"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"የመስሚያ መሣሪያዎች"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ግንኙነት ተቋርጧል"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"ተገናኝቷል"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"ገቢር"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"በመጫን ላይ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"የድምፅ ቁልፎችን ይዟል። <xliff:g id="SERVICE_NAME">%1$s</xliff:g> በርቷል።"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"የድምፅ ቁልፎችን ይዟል። <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ጠፍተዋል።"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"የድምጽ መጠን ቁልፎቹን ይልቀቁ። <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን ለማብራት ሁለቱንም የድምጽ መጠን ቁልፎች በድጋሚ ለ3 ሰከንዶች ተጭነው ይያዙ።"</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"ወደ ስልክ ማይክሮፎን ይቀየር?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"ወደ መስሚያ አጋዥ መሣሪያ ማይክሮፎን ይቀየር?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"የተሻለ ድምፅ ለማግኘት ወይም መስሚያ አጋዥ መሣሪያዎ ባትሪ ዝቅተኛ ከሆነ። ይህ በጥሪው ወቅት ማይክሮፎንዎን ብቻ ይቀይራል።"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"የእርስዎን መስሚያ አጋዥ መሣሪያ ማይክሮፎን ለነጻ እጅ መደወል መጠቀም ይችላሉ። ይህ በጥሪው ወቅት ማይክሮፎንዎን ብቻ ይቀይራል።"</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"ቀይር"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ቅንብሮች"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> በማውጣት ላይ…"</string>
@@ -2454,6 +2459,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"የሳተላይት መልዕክት መላላክን ይጠቀማሉ?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"ያለ ሞባይል ወይም የWi-Fi አውታረ መረብ መልዕክቶችን ይላኩ እና ይቀበሉ"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"መልዕክቶች ይክፈቱ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 02e5be1a36b1..cb765e71b801 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -91,8 +91,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"يتعذّر الوصول إلى شبكة الجوّال."</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"حاول تغيير الشبكة المفضلة. انقر لتغييرها."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"لا تتوفر إمكانية الاتصال في حالات الطوارئ."</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"عدم عرض هذا الإشعار مجددًا"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"يتطلّب إجراء مكالمات الطوارئ الاتصال بشبكة جوّال"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"التنبيهات"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"إعادة توجيه المكالمة"</string>
@@ -307,6 +306,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"تنبيهات الشبكة"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"الشبكة متوفرة"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"‏حالة شبكة VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"الوقت والمناطق الزمنية"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"التنبيهات من مشرف تكنولوجيا المعلومات"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"التنبيهات"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"عرض توضيحي لبائع التجزئة"</string>
@@ -314,6 +314,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"التطبيق قيد التشغيل"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"التطبيقات التي تستهلك البطارية"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"التكبير"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"سماعة الأذن الطبية"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"استخدام \"أدوات تسهيل الاستخدام\""</string>
<string name="notification_channel_display" msgid="6905032605735615090">"الشاشة"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"يستخدم تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> البطارية"</string>
@@ -1411,6 +1412,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"تنزيل التطبيق"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"‏تم إدخال شريحة SIM جديدة."</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"انقر لإعداده."</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"تم تغيير منطقتك الزمنية"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"أنت الآن في <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)."</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"ضبط الوقت"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"تعيين التاريخ"</string>
<string name="date_time_set" msgid="4603445265164486816">"ضبط"</string>
@@ -1784,14 +1787,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"وضع \"التصفح بيد واحدة\""</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"زيادة تعتيم الشاشة"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"سماعات الأذن الطبية"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"غير متّصل"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"متّصل"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"متّصل حاليًا"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"غير متاح بعد"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"تم الضغط مع الاستمرار على مفتاحَي التحكّم في مستوى الصوت. تم تفعيل <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"تم الضغط مع الاستمرار على مفتاحَي التحكّم في مستوى الصوت. تم إيقاف <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"ارفع إصبعَيك عن مفتاحَي مستوى الصوت. لتفعيل خدمة \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\"، اضغط مع الاستمرار على كلا مفتاحَي مستوى الصوت مجددًا لمدة 3 ثوانٍ."</string>
@@ -1802,6 +1801,12 @@
<string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"سيتم فتح الميزة عند استخدام هذا الاختصار في المرة القادمة. مرِّر سريعًا من أسفل الشاشة إلى أعلاها باستخدام إصبعَين وارفعما بعدها بسرعة."</string>
<string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"سيتم فتح الميزة عند استخدام هذا الاختصار في المرة القادمة. مرِّر سريعًا من أسفل الشاشة إلى أعلاها باستخدام 3 أصابع وارفع أصابعك بعدها بسرعة."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"التكبير"</string>
+ <string name="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"هل المطلوب التبديل إلى ميكروفون الهاتف؟"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"هل المطلوب التبديل إلى ميكروفون سماعة الأذن الطبية؟"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"ننصحك بالتبديل إذا أردت الحصول على صوت أفضل أو عند انخفاض طاقة بطارية سماعة الأذن الطبية. يؤدي هذا الإجراء إلى تبديل الميكروفون فقط أثناء المكالمة."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"يمكنك استخدام ميكروفون سماعة الأذن الطبية لإجراء مكالمات بدون لمس الجهاز. يؤدي هذا الإجراء إلى تبديل الميكروفون فقط أثناء المكالمة."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"تبديل"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"الإعدادات"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"جارٍ الخروج <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2458,6 +2463,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"هل تريد المراسلة عبر القمر الصناعي؟"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"‏يمكنك إرسال الرسائل واستلامها بدون شبكة الجوّال أو شبكة Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"فتح تطبيق \"الرسائل\""</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 9f3b263f84a6..48895bc41000 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ম’বাইল নেটৱৰ্কৰ লগত সংযোগ কৰিব পৰা নাই"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"পচন্দৰ নেটৱৰ্ক সলনি কৰি চেষ্টা কৰি চাওক। সলনি কৰিবলৈ টিপক।"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"জৰুৰীকালীন কল কৰাৰ সুবিধা উপলব্ধ নহয়"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"পুনৰাই নেদেখুৱাব"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"জৰুৰীকালীন কল কৰিবলৈ ম’বাইল নেটৱৰ্কৰ প্ৰয়োজন"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"সতৰ্কবাণীসমূহ"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"কল ফৰৱাৰ্ডিং"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"নেটৱৰ্ক সম্পৰ্কীয় সতৰ্কবাণী"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"নেটৱৰ্ক উপলব্ধ"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"ভিপিএনৰ স্থিতি"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"সময় আৰু সময় মণ্ডল"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"আপোনাৰ আইটি প্ৰশাসকৰ পৰা অহা সতৰ্কবাণী"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"সতৰ্কবাণীসমূহ"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"খুচুৰা ডেম\'"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"এপ্ চলি আছে"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"বেটাৰী খৰচ কৰা এপ্‌সমূহ"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"বিবৰ্ধন"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"শুনাৰ ডিভাইচ"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"সাধ্য সুবিধাৰ ব্যৱহাৰ"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"ডিছপ্লে’"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ বেটাৰী ব্যৱহাৰ কৰি আছে"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"এপ্ ডাউনল’ড কৰক"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"নতুন ছিম ভৰোৱা হৈছে"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"ছেট আপ কৰিবলৈ টিপক"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"আপোনাৰ সময় মণ্ডল সলনি হৈছে"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"আপুনি এতিয়া <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g>ত (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) আছে"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"সময় ছেট কৰক"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"তাৰিখ ছেট কৰক"</string>
<string name="date_time_set" msgid="4603445265164486816">"ছেট কৰক"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"এখন হাতেৰে ব্যৱহাৰ কৰাৰ ম’ড"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"অতিৰিক্তভাৱে পোহৰ কমোৱাৰ সুবিধা"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"শুনাৰ ডিভাইচ"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"সংযোগ বিচ্ছিন্ন হ’ল"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"সংযোগ কৰা হ’ল"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"সক্ৰিয় হৈ আছে"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"ল’ড হৈ আছে"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ভলিউম কীসমূহ ধৰি ৰাখক। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> অন কৰা হ\'ল।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ভলিউম কী ধৰি ৰাখিছিল। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> অফ কৰা হ\'ল।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"ভলিউম কী এৰি দিয়ক। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> অন কৰিবলৈ, দুয়োটা ভলিউম কী পুনৰ ৩ ছেকেণ্ডৰ বাবে টিপি হেঁচি ৰাখক।"</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"ফ’নৰ মাইকলৈ সলনি কৰিবনে?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"শ্ৰৱণ যন্ত্ৰৰ মাইকলৈ সলনি কৰিবনে?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"অধিক ভাল ধ্বনিৰ বাবে বা যদি আপোনাৰ শ্ৰৱণ যন্ত্ৰৰ বেটাৰীৰ চাৰ্জ কম থাকে। এইটোৱে কল চলি থাকোঁতে কেৱল আপোনাৰ মাইকটো সলনি কৰে।"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"আপুনি হেণ্ডছ্‌-ফ্ৰী কলিঙৰ বাবে আপোনাৰ শ্ৰৱণ যন্ত্ৰৰ মাইক্ৰ’ফ’ন ব্যৱহাৰ কৰিব পাৰে। এইটোৱে কল চলি থাকোঁতে কেৱল আপোনাৰ মাইকটো সলনি কৰে।"</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"সলনি কৰক"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ছেটিং"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g>ৰ পৰা লগ আউট কৰি থকা হৈছে…"</string>
@@ -2454,6 +2459,7 @@
<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">"আপুনি ম’বাইল বা ৱাই-ফাই নেটৱৰ্কৰ জৰিয়তে পাঠ বাৰ্তা পঠিয়াব বা লাভ কৰিব পাৰে"</string>
+ <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"আপুনি উপগ্ৰহৰ জৰিয়তে বাৰ্তা পঠিয়াব আৰু গ্ৰহণ কৰিব পাৰে আৰু সীমিত তথ্য ব্যৱহাৰ কৰিব পাৰে"</string>
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"উপগ্ৰহৰ জৰিয়তে বাৰ্তা বিনিময়ৰ সুবিধাটো ব্যৱহাৰ কৰিবনে?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"আপুনি কোনো ম’বাইল বা ৱাই-ফাই নেটৱৰ্ক নোহোৱাকৈ বাৰ্তা পঠিয়াওক আৰু লাভ কৰক"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages খোলক"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 54062de9536b..0a4597ec589e 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Mobil şəbəkəyə daxil olmaq mümkün deyil"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Tərcih edilən şəbəkəni dəyişin. Dəyişmək üçün klikləyin."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Təcili zəng əlçatan deyil"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Yenidən göstərməyin"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Təcili zənglər üçün mobil şəbəkə tələb olunur"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Siqnallar"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Zəng yönləndirmə"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Şəbəkə siqnalları"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Şəbəkə əlçatandır"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN statusu"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Vaxt və saat qurşaqları"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"IT adminindən xəbərdarlıqlar"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Siqnallar"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Pərakəndə demo"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Tətbiq işləyir"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Batareyadan istifadə edən tətbiqlər"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Böyütmə"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Eşitmə cihazı"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Əlçatımlılıq istifadəsi"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Displey"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> batareyadan istifadə edir"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Tətbiqi endirin"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Yeni SIM kart taxılıb"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Quraşdırmaq üçün tıklayın"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Saat qurşağınız dəyişildi"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Hazırda saat qurşağınız: <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Vaxt ayarlayın"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Tarixi quraşdır"</string>
<string name="date_time_set" msgid="4603445265164486816">"Ayarlayın"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Birəlli rejim"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Əlavə tündləşmə"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Eşitmə cihazları"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Bağlantı kəsildi"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Qoşuldu"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktivdir"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Yüklənir"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Səs səviyyəsi düymələrinə basıb saxlayın. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktiv edildi."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Səs səviyyəsi düymələrinə basılaraq saxlanıb. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> deaktiv edilib."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Səs düymələrini buraxın. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> xidmətini aktiv etmək üçün hər iki səs düyməsinə yenidən 3 saniyə basıb saxlayın."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Telefon mikrofonuna dəyişilsin?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Eşitmə aparatı mikrofonuna dəyişdirilsin?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Daha yaxşı səs üçün və ya eşitmə aparatınızın batareyası azdırsa. Bu, yalnız zəng zamanı mikrofonu dəyişdirir."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Səsli idarəetmə ilə zəng etmək üçün eşitmə aparatı mikrofonunuzdan istifadə edə bilərsiniz. Bu, yalnız zəng zamanı mikrofonu dəyişdirir."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Dəyişin"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Ayarlar"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> çıxır..."</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Tətbiq kontenti güvənlik məsələlərinə görə ekran paylaşımından gizlədildi"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Peykə avtomatik qoşulub"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Mobil və ya Wi-Fi şəbəkəsi olmadan mesaj göndərə və qəbul edə bilərsiniz"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Peyk mesajlaşmasından istifadə edilsin?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Mobil və ya Wi-Fi şəbəkəsi olmadan mesajlar göndərin və qəbul edin"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Mesajı açın"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 69b46124cec1..5fb744ee2fa9 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -88,8 +88,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Povezivanje sa mobilnom mrežom nije uspelo"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Probajte da promenite željenu mrežu. Dodirnite da biste promenili."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Hitni pozivi nisu dostupni"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Ne prikazuj ponovo"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Hitni pozivi zahtevaju mobilnu mrežu"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Upozorenja"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Preusmeravanje poziva"</string>
@@ -304,6 +303,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Obaveštenja u vezi sa mrežom"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Mreža je dostupna"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Status VPN-a"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Vreme i vremenske zone"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Obaveštenja od IT administratora"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Upozorenja"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Režim demonstracije za maloprodajne objekte"</string>
@@ -311,6 +311,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Aktivna aplikacija"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Aplikacije koje troše bateriju"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Uvećanje"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Slušni aparat"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Korišćenje Pristupačnosti"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Ekran"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> koristi bateriju"</string>
@@ -1408,6 +1409,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Preuzmite aplikaciju"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Nova SIM kartica je umetnuta"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Dodirnite za podešavanje"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Vremenska zona je promenjena"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Sada ste u vremenskoj zoni <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Podesite vreme"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Podešavanje datuma"</string>
<string name="date_time_set" msgid="4603445265164486816">"Podesi"</string>
@@ -1781,14 +1784,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Režim jednom rukom"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Dodatno zatamni"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Slušni aparati"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Veza je prekinuta"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Povezano"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktivno"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Učitava se"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tastere za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je uključena."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tastere za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je isključena."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Pustite tastere za jačinu zvuka. Da biste uključili <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, ponovo pritisnite i zadržite oba tastera za jačinu zvuka 3 sekunde."</string>
@@ -1799,6 +1798,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Želite da pređete na mikrofon telefona?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Želite da pređete na mikrofon slušnog aparata?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Za bolji zvuk ili ako je baterija slušnog aparata skoro prazna. Time se mikrofon menja samo tokom poziva."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Možete da koristite mikrofon slušnog aparata za hendsfri pozivanje. Time se mikrofon menja samo tokom poziva."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Promeni"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Podešavanja"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Odjavljuje se <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2455,6 +2460,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije je skriven za deljenje sadržaja ekrana zbog bezbednosti"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Automatski povezano sa satelitom"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Možete da šaljete i primate poruke bez mobilne ili WiFi mreže"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Želite da koristite satelitsku razmenu poruka?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Šaljite i primajte poruke bez mobilne ili WiFi mreže"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvori Messages"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 9f7f823fdec0..74c0b46a8045 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -89,8 +89,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Сетка мабільнай сувязі недаступная"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Націсніце, каб выбраць іншую сетку."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Экстранныя выклікі недаступныя"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Больш не паказваць"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Для экстранных выклікаў патрабуецца мабільная сетка"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Абвесткі"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Пераадрасацыя выкліку"</string>
@@ -305,6 +304,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Абвесткі сеткі"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Сетка даступная"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Стан VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Час і часавыя паясы"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Абвесткі ад IT-адміністратара"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Абвесткi"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Дэманстрацыйны рэжым для пунктаў продажу"</string>
@@ -312,6 +312,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Праграма працуе"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Праграмы, якія выкарыстоўваюць акумулятар"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Павелічэнне"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Слыхавы апарат"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Выкарыстанне спецыяльных магчымасцей"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Дысплэй"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> выкарыстоўвае акумулятар"</string>
@@ -1409,6 +1410,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Спампаваць праграму"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Устаўлена новая SIM-карта"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Краніце, каб наладзіць"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Ваш часавы пояс зменены"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Ваш часавы пояс: <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Задаць час"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Задаць дату"</string>
<string name="date_time_set" msgid="4603445265164486816">"Задаць"</string>
@@ -1782,14 +1785,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Рэжым кіравання адной рукой"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Дадатковае памяншэнне яркасці"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слыхавыя апараты"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Адключана"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Падключана"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Актыўная"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Ідзе загрузка"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Клавішы гучнасці ўтрымліваліся націснутымі. Уключана служба \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\"."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Клавішы гучнасці ўтрымліваліся націснутымі. Служба \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\" выключана."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Адпусціце клавішы гучнасці. Каб уключыць сэрвіс \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\", націсніце абедзве клавішы гучнасці яшчэ раз і ўтрымлівайце іх на працягу 3 секунд."</string>
@@ -1800,6 +1799,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Пераключыцца на мікрафон тэлефона?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Пераключыцца на мікрафон слыхавога апарата?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Для паляпшэння якасці гуку або пры нізкім узроўні зараду акумулятара слыхавога апарата. Будзе пераключаны толькі ваш мікрафон."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Вы можаце выкарыстоўваць мікрафон слыхавога апарата, каб размаўляць падчас званка без дапамогі рук. Будзе пераключаны толькі ваш мікрафон."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Пераключыцца"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Налады"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> выходзіць з сістэмы…"</string>
@@ -2456,6 +2461,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Выкарыстоўваць абмен паведамленнямі па спадарожнікавай сувязі?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Вы можаце адпраўляць і атрымліваць паведамленні, калі падключэнне да мабільнай сеткі або сеткі Wi-Fi адсутнічае"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Адкрыць Паведамленні"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 1353d2287c09..b857fb52b418 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Не може да се установи връзка с мобилната мрежа"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Изберете друга предпочитана мрежа. Докоснете за промяна."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Няма достъп до спешните обаждания"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Да не се показва отново"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"За спешните обаждания се изисква мобилна мрежа"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Сигнали"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Пренасочване на обаждания"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Сигнали за мрежата"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Налице е мрежа"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Състояние на VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Час и часови зони"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Сигнали от системния ви администратор"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Сигнали"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Демонстрационен режим за магазини"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Приложението работи"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Приложения, използващи батерията"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Увеличение"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Слухов апарат"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Използване на услугите за достъпност"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Дисплей"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> използва батерията"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Изтегляне на приложението"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Поставена е нова SIM карта"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Докоснете, за да я настроите"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Часовата ви зона се промени"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Вече сте в зоната <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Задаване на часа"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Задаване на дата"</string>
<string name="date_time_set" msgid="4603445265164486816">"Задаване"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Работа с една ръка"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Допълнително затъмняване"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слухови апарати"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Няма връзка"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Свързано"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Активно"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Зарежда се"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Задържахте бутоните за силата на звука. Услугата <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е включена."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Задържахте бутоните за силата на звука. Услугата <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е изключена."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Освободете бутоните за силата на звука. За да включите <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, отново натиснете двата бутона за силата на звука и задръжте за 3 секунди."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Да се превключи ли към микрофона на телефона?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Да се превключи ли към микрофона на слуховия апарат?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"За по-добър звук или ако батерията на слуховия ви апарат е изтощена. Микрофонът ще бъде включен само по време на обаждането."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Можете да използвате микрофона на слуховия си апарат за обаждания в режим „свободни ръце“. Микрофонът ще бъде включен само по време на обаждането."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Превключване"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Настройки"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> излиза…"</string>
@@ -2454,6 +2459,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Да се използват ли сателитни съобщения?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Изпращайте и получавайте съобщения без мобилна или Wi-Fi мрежа"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Отваряне на Messages"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index d74a3a375159..8da67849c84d 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"মোবাইল নেটওয়ার্কে কানেক্ট করা যাচ্ছে না"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"পছন্দের নেটওয়ার্ক পরিবর্তন করে দেখুন। অন্য নেটওয়ার্ক বেছে নিতে ট্যাপ করুন।"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"জরুরি কল করা যাবে না"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"আর দেখতে চাই না"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"জরুরি কলের জন্য মোবাইল নেটওয়ার্ক থাকতে হবে"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"সতর্কতা"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"কল ফরওয়ার্ড করা"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"নেটওয়ার্ক সক্রান্ত অ্যালার্ট"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"নেটওয়ার্ক পাওয়া যাচ্ছে"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN এর স্থিতি"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"সময় এবং টাইম জোন"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"আপনার আইটি অ্যাডমিনের সতর্কতা"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"সতর্কতা"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"খুচরা বিক্রয়ের ডেমো"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"অ্যাপ চলছে"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"কিছু অ্যাপ ব্যাটারি ব্যবহার করছে"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"বড় করে দেখা"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"হিয়ারিং ডিভাইস"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"অ্যাক্সেসিবিলিটি সংক্রান্ত ব্যবহার"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"ডিসপ্লে"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপটি ব্যাটারি ব্যবহার করছে"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"অ্যাপ ডাউনলোড করুন"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"নতুন সিম ঢোকানো হয়েছে"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"এটিকে সেট-আপ করতে আলতো চাপুন"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"আপনার টাইম জোন পরিবর্তন হয়ে গেছে"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"আপনি এখন <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)-এ আছেন"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"সময় সেট করুন"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"তারিখ সেট করুন"</string>
<string name="date_time_set" msgid="4603445265164486816">"সেট করুন"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"এক হাতে ব্যবহার করার মোড"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"অতিরিক্ত কম উজ্জ্বলতা"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"হিয়ারিং ডিভাইস"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ডিসকানেক্ট হয়ে গেছে"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"কানেক্ট করা হয়েছে"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"অ্যাক্টিভ"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"লোড হচ্ছে"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ভলিউম কী ধরে ছিলেন। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> চালু করা হয়েছে।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ভলিউম কী ধরে ছিলেন। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> বন্ধ করা হয়েছে।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"ভলিউম \'কী\' রিলিজ করুন। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> চালু করুন, দু\'টি ভলিউম \'কী\' আবার প্রেস করে ৩ সেকেন্ড ধরে রাখুন।"</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"ফোনের মাইকে পরিবর্তন করবেন?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"হিয়ারিং এড মাইকে পরিবর্তন করবেন?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"আরও ভালো সাউন্ডের জন্য অথবা আপনার হিয়ারিং এডের ব্যাটারি যদি কম থাকে। এটি শুধুমাত্র কল চলাকালীন আপনার মাইক পরিবর্তন করে।"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"হ্যান্ডস-ফ্রি কলিংয়ের জন্য আপনার হিয়ারিং এডের মাইক্রোফোন ব্যবহার করতে পারবেন। এটি শুধুমাত্র কল চলাকালীন আপনার মাইক পরিবর্তন করে।"</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"পরিবর্তন করুন"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"সেটিংস"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g>কে লগ-আউট করা হচ্ছে..."</string>
@@ -2454,6 +2459,8 @@
<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">"আপনি কোনও মেবাইল বা ওয়াই-ফাই নেটওয়ার্ক ছাড়াই মেসেজ পাঠাতে ও পেতে পারবেন"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"\'স্যাটেলাইট মেসেজিং\' ব্যবহার করবেন?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"কোনও মেবাইল বা ওয়াই-ফাই নেটওয়ার্ক ছাড়াই মেসেজ পাঠান ও রিসিভ করুন"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages খুলুন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index c9168709eb08..639972915f76 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -88,8 +88,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Nije moguće dosegnuti mobilnu mrežu"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Pokušajte promijeniti preferiranu mrežu. Dodirnite za promjenu."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Hitni pozivi su nedostupni"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Ne prikazuj ponovo"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Za hitne pozive potrebna je mreža"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Upozorenja"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Prosljeđivanje poziva"</string>
@@ -304,6 +303,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Mrežna upozorenja"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Mreža je dostupna"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Status VPN-a"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Vrijeme i vremenske zone"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Upozorenja od IT administratora"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Upozorenja"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Prodajna demonstracija"</string>
@@ -311,6 +311,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Pokrenuta aplikacija"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Aplikacije koje troše bateriju"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Uvećavanje"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Slušni aparat"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Korištenje pristupačnosti"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Ekran"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> troši bateriju"</string>
@@ -1408,6 +1409,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Preuzmite aplikaciju"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Nova SIM kartica je umetnuta"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Dodirnite da biste postavili"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Vremenska zona je promijenjena"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Sada ste u vremenskoj zoni <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Postavljanje vremena"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Postavljanje datuma"</string>
<string name="date_time_set" msgid="4603445265164486816">"Postaviti"</string>
@@ -1781,14 +1784,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Način rada jednom rukom"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Dodatno zatamnjenje"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Slušni aparati"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Nije povezano"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Povezano"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktivno"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Učitavanje"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tipke za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je uključena."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tipke za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je isključena."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Pustite tipke za jačinu zvuka. Da uključite uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, ponovo pritisnite i zadržite obje tipke za jačinu zvuka 3 sekunde."</string>
@@ -1799,6 +1798,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Promijeniti na mikrofon telefona?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Promijeniti na mikrofon slušnog aparata?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Za bolji zvuk ili ako je baterija slušnog aparata slaba. Ovo mijenja mikrofon samo tokom poziva."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Možete koristiti mikrofon slušnog aparata za pozivanje bez dodira. Ovo mijenja mikrofon samo tokom poziva."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Promijeni"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Postavke"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Odjava korisnika <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2455,6 +2460,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije je sakriven od dijeljenja ekrana radi sigurnosti"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Automatski je povezano sa satelitom"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Možete slati i primati poruke bez mobilne ili WiFi mreže"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Koristiti satelitsku razmjenu poruka?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Šaljite i primajte poruke bez mobilne ili WiFi mreže"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvorite Messages"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 5c53857c5902..49d80c25cbfc 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -88,8 +88,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"No es pot accedir a la xarxa mòbil"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Prova de canviar de xarxa preferent. Toca per canviar-la."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Les trucades d\'emergència no estan disponibles"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"No ho tornis a mostrar"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Per poder fer trucades d\'emergència, cal tenir connexió de xarxa mòbil"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertes"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Desviació de trucades"</string>
@@ -304,6 +303,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Alertes de xarxa"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Hi ha una xarxa disponible"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Estat de la VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Hora i zones horàries"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Alertes de l\'administrador de TI"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Alertes"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demostració per a botigues"</string>
@@ -311,6 +311,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Aplicació en execució"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Aplicacions que consumeixen bateria"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Ampliació"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Audiòfon"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Ús de les funcions d\'accessibilitat"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Pantalla"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> està consumint bateria"</string>
@@ -1408,6 +1409,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Baixa l\'aplicació"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"S\'ha inserit una SIM nova"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Toca per configurar-la"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"La zona horària ha canviat"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Ara ets a <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Defineix l\'hora"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Establiment de data"</string>
<string name="date_time_set" msgid="4603445265164486816">"Defineix"</string>
@@ -1781,14 +1784,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mode d\'una mà"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Atenuació extra"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Audiòfons"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desconnectat"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connectat"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Actiu"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"S\'està carregant"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"S\'han mantingut premudes les tecles de volum. S\'ha activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"S\'han mantingut premudes les tecles de volum. S\'ha desactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Deixa anar les tecles de volum. Per activar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, torna a mantenir premudes totes dues tecles de volum durant 3 segons."</string>
@@ -1799,6 +1798,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Vols canviar al micròfon del telèfon?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Vols canviar al micròfon de l\'audiòfon?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Per obtenir un so millor o si l\'audiòfon té poca bateria. Aquesta opció només canvia el micròfon durant la trucada."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Pots fer servir el micròfon del teu audiòfon per fer trucades amb mans lliures. Aquesta opció només canvia el micròfon durant la trucada."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Canvia"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Configuració"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"S\'està tancant la sessió de l\'usuari <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2455,6 +2460,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Contingut de l\'aplicació amagat de la compartició de pantalla per seguretat"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"S\'ha connectat automàticament a un satèl·lit"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Pots enviar i rebre missatges sense una xarxa mòbil o Wi‑Fi"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Vols utilitzar els missatges per satèl·lit?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Envia i rep missatges sense una xarxa mòbil o Wi‑Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Obre Missatges"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 8d595d893ead..8b45d72f9131 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -89,8 +89,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Mobilní síť není dostupná"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Zkuste změnit preferovanou síť. Změníte ji klepnutím."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Tísňová volání jsou nedostupná"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Už nezobrazovat"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Tísňová volání vyžadují mobilní síť"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Upozornění"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Přesměrování hovorů"</string>
@@ -305,6 +304,8 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Síťová upozornění"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"K dispozici je síť"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Stav sítě VPN"</string>
+ <!-- no translation found for notification_channel_system_time (1660313368058030441) -->
+ <skip />
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Upozornění od vašeho administrátora IT"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Upozornění"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Prodejní ukázka"</string>
@@ -312,6 +313,8 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Aplikace je spuštěna"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Aplikace spotřebovávají baterii"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Zvětšení"</string>
+ <!-- no translation found for notification_channel_accessibility_hearing_device (7816963856388758952) -->
+ <skip />
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Využití přístupnosti"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Displej"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> využívá baterii"</string>
@@ -1409,6 +1412,10 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Stáhnout aplikaci"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Byla vložena nová SIM karta"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Klepnutím zahájíte nastavení"</string>
+ <!-- no translation found for time_zone_change_notification_title (5232503069219193218) -->
+ <skip />
+ <!-- no translation found for time_zone_change_notification_body (6135793674904665585) -->
+ <skip />
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Nastavit čas"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Nastavení data"</string>
<string name="date_time_set" msgid="4603445265164486816">"Nastavit"</string>
@@ -1782,14 +1789,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Režim jedné ruky"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Velmi tmavé zobrazení"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Naslouchátka"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Odpojeno"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Připojeno"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktivní"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Načítání"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Byla podržena tlačítka hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je zapnutá."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Byla podržena tlačítka hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> byla vypnuta."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Uvolněte tlačítka hlasitosti. Pokud chcete zapnout službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, znovu tři sekundy podržte obě tlačítka hlasitosti."</string>
@@ -1800,6 +1803,18 @@
<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>
+ <!-- no translation found for hearing_device_switch_phone_mic_notification_title (6645178038359708836) -->
+ <skip />
+ <!-- no translation found for hearing_device_switch_hearing_mic_notification_title (4612074852145289569) -->
+ <skip />
+ <!-- no translation found for hearing_device_switch_phone_mic_notification_text (1332426273666077412) -->
+ <skip />
+ <!-- no translation found for hearing_device_switch_hearing_mic_notification_text (8288368365767284208) -->
+ <skip />
+ <!-- no translation found for hearing_device_notification_switch_button (3619524619430941300) -->
+ <skip />
+ <!-- no translation found for hearing_device_notification_settings_button (6673651052880279178) -->
+ <skip />
<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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Odhlašování uživatele <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2456,6 +2471,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Obsah aplikace je z bezpečnostních důvodů při sdílení obrazovky skryt"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Automaticky připojeno k satelitu"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Zprávy můžete odesílat a přijímat bez mobilní sítě nebo sítě Wi-Fi"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Použít satelitní zprávy?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Odesílejte a přijímejte zprávy bez mobilní sítě nebo Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Otevřít Zprávy"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 66e3402c1ebf..edd910c9fe6d 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Der er ingen forbindelse til mobilnetværket"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Prøv at skifte dit foretrukne netværk. Tryk for skifte."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Det er ikke muligt at foretage nødopkald"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Vis ikke igen"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Nødopkald kræver adgang til et mobilnetværk"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Underretninger"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Viderestilling af opkald"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Netværksunderretninger"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Tilgængeligt netværk"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN-status"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Klokkeslæt og tidszoner"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Underretninger fra din it-administrator"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Underretninger"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demo til udstilling i butik"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Appen kører"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Apps, der bruger batteri"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Forstørrelse"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Høreapparat"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Brug af hjælpefunktioner"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Skærm"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> bruger batteri"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Download app"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Nyt SIM-kort er indsat"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Tryk for at konfigurere"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Din tidszone blev ændret"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Du er nu i <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Angiv tidspunkt"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Angiv dato"</string>
<string name="date_time_set" msgid="4603445265164486816">"Angiv"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Enhåndstilstand"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra dæmpet belysning"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Høreapparater"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Ikke forbundet"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Forbundet"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktiv"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Indlæser"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Lydstyrkeknapperne blev holdt nede. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er aktiveret."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Lydstyrkeknapperne blev holdt nede. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er deaktiveret."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Slip lydstyrkeknapperne. Du kan aktivere <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ved at holde begge lydstyrkeknapper nede igen i 3 sekunder."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Vil du skifte til telefonens mikrofon?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Vil du skifte til mikrofonen i høreapparatet?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"For at få bedre lyd, eller hvis dit høreapparat er ved at løbe tør for batteri. Der skiftes kun mikrofon under opkaldet."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Du kan bruge mikrofonen i dit høreapparat til at foretage håndfrie opkald. Der skiftes kun mikrofon under opkaldet."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Skift"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Indstillinger"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> logges ud…"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Af sikkerhedsmæssige årsager vises appindhold ikke ved skærmdeling"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Der blev automatisk oprettet forbindelse til satellit"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Du kan sende og modtage beskeder uden et mobil- eller Wi-Fi-netværk"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Vil du bruge satellitbeskeder?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Send og modtag beskeder uden et mobil- eller Wi-Fi-netværk"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Åbn Beskeder"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 6311880bb24a..5262da98d277 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Mobilfunknetz nicht erreichbar"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Versuche, das bevorzugte Netzwerk zu ändern. Tippe, um ein anderes auszuwählen."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Notrufe nicht möglich"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Nicht noch einmal anzeigen"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Für Notrufe ist ein Mobilfunknetz erforderlich"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Warnmeldungen"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Anrufweiterleitung"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Netzwerkwarnungen"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Netzwerk verfügbar"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN-Status"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Uhrzeit und Zeitzonen"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Benachrichtigungen zu wichtigen Updates von deinem IT-Administrator"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Warnmeldungen"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demo für Einzelhandel"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"App wird ausgeführt"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Strom verbrauchende Apps"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Vergrößerung"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Hörgerät"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Nutzung der Bedienungshilfen"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Display"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> verbraucht Strom"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"App herunterladen"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Neue SIM-Karte eingelegt"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Zum Einrichten tippen"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Die Zeitzone hat sich geändert"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Du bist jetzt in <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Uhrzeit festlegen"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Datum festlegen"</string>
<string name="date_time_set" msgid="4603445265164486816">"Speichern"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Einhandmodus"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extradunkel"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hörgeräte"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Nicht verbunden"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Verbunden"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktiv"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Wird geladen"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Lautstärketasten wurden gedrückt gehalten. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ist aktiviert."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Lautstärketasten wurden gedrückt gehalten. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ist deaktiviert."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Lass die Lautstärketasten los. Halte zum Aktivieren von <xliff:g id="SERVICE_NAME">%1$s</xliff:g> beide Lautstärketasten noch einmal 3 Sekunden lang gedrückt."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Zum Mikrofon des Smartphones wechseln?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Zum Mikrofon des Hörgeräts wechseln?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Zum Verbessern des Tons oder wenn der Akkustand des Hörgeräts niedrig ist. Das Mikrofon wird nur für die Dauer des Anrufs gewechselt."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Du kannst das Mikrofon deines Hörgeräts für Anrufe per Sprachbefehl verwenden. Das Mikrofon wird nur für die Dauer des Anrufs gewechselt."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Wechseln"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Einstellungen"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> wird abgemeldet…"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Aus Sicherheitsgründen werden bei der Bildschirmfreigabe App-Inhalte ausgeblendet"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Automatisch mit Satellit verbunden"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Du kannst Nachrichten ohne Mobilfunknetz oder WLAN senden und empfangen"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Nachrichten per Satellit verwenden?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Du kannst ohne Mobilgerät oder WLAN Nachrichten senden und empfangen"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages öffnen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 23fc44ca9dcc..1d194f4e3b22 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Δεν είναι δυνατή η σύνδεση στο δίκτυο κινητής τηλεφωνίας"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Δοκιμάστε να αλλάξετε το προτιμώμενο δίκτυο. Πατήστε για αλλαγή."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Οι κλήσεις έκτακτης ανάγκης δεν είναι διαθέσιμες"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Να μην εμφανιστεί ξανά"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Για τις κλήσεις έκτακτης ανάγκης απαιτείται δίκτυο κινητής τηλεφωνίας"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Ειδοποιήσεις"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Προώθηση κλήσης"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Ειδοποιήσεις δικτύου"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Το δίκτυο είναι διαθέσιμο"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Κατάσταση VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Ώρα και ζώνες ώρας"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Ειδοποιήσεις από τον διαχειριστή IT"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Ειδοποιήσεις"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Επίδειξη λιανικής"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Η εφαρμογή εκτελείται"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Εφαρμογές που καταναλώνουν μπαταρία"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Μεγιστοποίηση"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Συσκευή ακοής"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Χρήση προσβασιμότητας"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Οθόνη"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> χρησιμοποιεί μπαταρία"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Λήψη εφαρμογής"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Τοποθετήθηκε νέα SIM"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Πατήστε για ρύθμιση"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Η ζώνη ώρας άλλαξε"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Βρίσκεστε πλέον στη ζώνη ώρας <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Ρύθμιση ώρας"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Ορισμός ημερομηνίας"</string>
<string name="date_time_set" msgid="4603445265164486816">"Ορισμός"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Λειτουργία ενός χεριού"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Επιπλέον μείωση φωτεινότητας"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Συσκευές ακοής"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Αποσυνδέθηκε"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Συνδέθηκε"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Ενεργή"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Φόρτωση"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Τα πλήκτρα έντασης είναι πατημένα. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ενεργοποιήθηκε."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Τα πλήκτρα έντασης είναι πατημένα. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>: απενεργοποιημένο"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Αφήστε τα κουμπιά έντασης ήχου. Για να ενεργοποιήσετε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, πατήστε ξανά παρατεταμένα και τα δύο κουμπιά έντασης ήχου για τρία δευτερόλεπτα."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Εναλλαγή στο μικρόφωνο του τηλεφώνου;"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Εναλλαγή στο μικρόφωνο του βοηθήματος ακοής;"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Για καλύτερο ήχο ή αν η μπαταρία του βοηθήματος ακοής είναι χαμηλή. Με αυτή την ενέργεια, το μικρόφωνό σας αλλάζει μόνο κατά τη διάρκεια της κλήσης."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Μπορείτε να χρησιμοποιήσετε το μικρόφωνο του βοηθήματος ακοής σας για κλήσεις handsfree. Με αυτή την ενέργεια, το μικρόφωνό σας αλλάζει μόνο κατά τη διάρκεια της κλήσης."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Εναλλαγή"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Ρυθμίσεις"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Αποσύνδεση <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2454,6 +2459,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Χρήση της ανταλλαγής μηνυμάτων μέσω δορυφόρου;"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Αποστολή και λήψη μηνυμάτων χωρίς δίκτυο κινητής τηλεφωνίας ή Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Άνοιγμα Messages"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 823db75ca6f4..75432f8b59a6 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Can’t reach mobile network"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Try changing preferred network. Tap to change."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Emergency calling unavailable"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Do not show again"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Emergency calls require a mobile network"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alerts"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Call forwarding"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Network alerts"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Network available"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN status"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Time and time zones"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Alerts from your IT admin"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Alerts"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Retail demo"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"App running"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Apps consuming battery"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Magnification"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Hearing device"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Accessibility usage"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Display"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> is using battery"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Download app"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"New SIM inserted"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Tap to set it up"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Your time zone changed"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"You\'re now in <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Set time"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Set date"</string>
<string name="date_time_set" msgid="4603445265164486816">"Set"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"One-handed mode"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dim"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hearing devices"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Disconnected"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connected"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Active"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Loading"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Release the volume keys. To turn on <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, press and hold both volume keys again for three seconds."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Switch to phone mic?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Switch to hearing aid mic?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"For better sound or if your hearing aid battery is low. This only switches your mic during the call."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"You can use your hearing aid microphone for hands-free calling. This only switches your mic during the call."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Switch"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Settings"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Logging out <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Auto-connected to satellite"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"You can send and receive messages without a mobile or Wi-Fi network"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Use satellite messaging?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Send and receive messages without a mobile or Wi-Fi network"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Open Messages"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 83fd1186e006..fc4b8af6f0ba 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -302,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Network alerts"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Network available"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN status"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Time and time zones"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Alerts from your IT admin"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Alerts"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Retail demo"</string>
@@ -309,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"App running"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Apps consuming battery"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Magnification"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Hearing device"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Accessibility usage"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Display"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> is using battery"</string>
@@ -1406,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Download app"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"New SIM inserted"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Tap to set it up"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Your time zone changed"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"You\'re now in <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Set time"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Set date"</string>
<string name="date_time_set" msgid="4603445265164486816">"Set"</string>
@@ -1779,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"One-Handed mode"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dim"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hearing devices"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Disconnected"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connected"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Active"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Loading"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Release the volume keys. To turn on <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, press and hold both volume keys again for 3 seconds."</string>
@@ -1797,6 +1797,12 @@
<string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"The feature will open next time 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 next time 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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Switch to phone mic?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Switch to hearing aid mic?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"For better sound or if your hearing aid battery is low. This only switches your mic during the call."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"You can use your hearing aid microphone for hands-free calling. This only switches your mic during the call."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Switch"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Settings"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Logging out <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2453,6 +2459,7 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Auto connected to satellite"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"You can send and receive messages without a mobile or Wi-Fi network"</string>
+ <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"You can send and receive messages and use limited data by satellite"</string>
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Use satellite messaging?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Send and receive messages without a mobile or Wi-Fi network"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Open Messages"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 46a0d2b96869..7d642b71028d 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Can’t reach mobile network"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Try changing preferred network. Tap to change."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Emergency calling unavailable"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Do not show again"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Emergency calls require a mobile network"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alerts"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Call forwarding"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Network alerts"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Network available"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN status"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Time and time zones"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Alerts from your IT admin"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Alerts"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Retail demo"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"App running"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Apps consuming battery"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Magnification"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Hearing device"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Accessibility usage"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Display"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> is using battery"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Download app"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"New SIM inserted"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Tap to set it up"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Your time zone changed"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"You\'re now in <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Set time"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Set date"</string>
<string name="date_time_set" msgid="4603445265164486816">"Set"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"One-handed mode"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dim"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hearing devices"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Disconnected"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connected"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Active"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Loading"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Release the volume keys. To turn on <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, press and hold both volume keys again for three seconds."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Switch to phone mic?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Switch to hearing aid mic?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"For better sound or if your hearing aid battery is low. This only switches your mic during the call."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"You can use your hearing aid microphone for hands-free calling. This only switches your mic during the call."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Switch"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Settings"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Logging out <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Auto-connected to satellite"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"You can send and receive messages without a mobile or Wi-Fi network"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Use satellite messaging?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Send and receive messages without a mobile or Wi-Fi network"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Open Messages"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 22cf48f71439..dd8e69550fff 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Can’t reach mobile network"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Try changing preferred network. Tap to change."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Emergency calling unavailable"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Do not show again"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Emergency calls require a mobile network"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alerts"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Call forwarding"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Network alerts"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Network available"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN status"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Time and time zones"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Alerts from your IT admin"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Alerts"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Retail demo"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"App running"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Apps consuming battery"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Magnification"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Hearing device"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Accessibility usage"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Display"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> is using battery"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Download app"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"New SIM inserted"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Tap to set it up"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Your time zone changed"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"You\'re now in <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Set time"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Set date"</string>
<string name="date_time_set" msgid="4603445265164486816">"Set"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"One-handed mode"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dim"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hearing devices"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Disconnected"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connected"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Active"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Loading"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Release the volume keys. To turn on <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, press and hold both volume keys again for three seconds."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Switch to phone mic?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Switch to hearing aid mic?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"For better sound or if your hearing aid battery is low. This only switches your mic during the call."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"You can use your hearing aid microphone for hands-free calling. This only switches your mic during the call."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Switch"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Settings"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Logging out <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Auto-connected to satellite"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"You can send and receive messages without a mobile or Wi-Fi network"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Use satellite messaging?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Send and receive messages without a mobile or Wi-Fi network"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Open Messages"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index b956286b7d2f..3451d58fe747 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -88,8 +88,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"No se puede acceder a la red móvil"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Presiona para cambiar la red preferida."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Servicio de llamadas de emergencia no disponible"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"No volver a mostrar"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Las llamadas de emergencia requieren una red móvil"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertas"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Desvío de llamada"</string>
@@ -304,6 +303,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Alertas de red"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Red disponible"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Estado de VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Hora y zonas horarias"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Alertas de tu administrador de TI"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Alertas"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demo para punto de venta"</string>
@@ -311,6 +311,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"App en ejecución"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Apps que consumen batería"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Ampliación"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Dispositivos auditivos"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Uso de accesibilidad"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Pantalla"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> está consumiendo batería"</string>
@@ -1408,6 +1409,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Descargar app"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Nueva SIM insertada"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Presiona para configurar"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Se cambió tu zona horaria"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Ahora estás en <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Configurar hora"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Configurar fecha"</string>
<string name="date_time_set" msgid="4603445265164486816">"Establecer"</string>
@@ -1781,14 +1784,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo de una mano"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Atenuación extra"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Dispositivos auditivos"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desconectado"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Conectado"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Activo"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Cargando"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Como mantuviste presionadas las teclas de volumen, se activó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Se presionaron las teclas de volumen. Se desactivó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Suelta las teclas de volumen. Para activar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, vuelve a mantener presionadas las teclas de volumen durante 3 segundos."</string>
@@ -1799,6 +1798,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"¿Quieres cambiar al micrófono del teléfono?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"¿Quieres cambiar al micrófono del audífono?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Para conseguir un mejor sonido o si la batería de tu audífono está baja. Esto solo cambia el micrófono durante la llamada."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Puedes usar el micrófono de tu audífono para realizar llamadas sin usar las manos. Esto solo cambia el micrófono durante la llamada."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Cambiar"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Configuració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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Saliendo de <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2455,6 +2460,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Se ocultó el contenido de la app durante el uso compartido de la pantalla por motivos de seguridad"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Conexión automática a satélite"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Puedes enviar y recibir mensajes incluso si no tienes conexión a una red móvil o Wi-Fi"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"¿Quieres usar la mensajería satelital?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Envía y recibe mensajes sin una red móvil ni Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir Mensajes"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index c50fbc7910ec..7b9dd4675800 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -88,8 +88,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"No se puede establecer conexión con la red móvil"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Toca para cambiar la red preferida."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Servicio de llamadas de emergencia no disponible"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"No volver a mostrar"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Para hacer llamadas de emergencia, necesitas conectarte a una red móvil"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertas"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Desvío de llamadas"</string>
@@ -304,6 +303,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Alertas de la red"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Red disponible"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Estado de la VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Hora y zonas horarias"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Alertas de tu administrador de TI"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Alertas"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demo para tiendas"</string>
@@ -311,6 +311,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Aplicación en ejecución"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Aplicaciones que consumen batería"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Ampliación"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Audífono"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Uso de accesibilidad"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Pantalla"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> está usando la batería"</string>
@@ -1408,6 +1409,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Descargar aplicación"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Nueva SIM insertada"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Toca para configurar"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Tu zona horaria ha cambiado"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Ahora estás en <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Establecer hora"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Establecer fecha"</string>
<string name="date_time_set" msgid="4603445265164486816">"Establecer"</string>
@@ -1781,14 +1784,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo Una mano"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Atenuación extra"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Audífonos"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desconectado"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Conectado"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Activo"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Cargando"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Al mantener pulsadas las teclas de volumen, se ha activado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Se han mantenido pulsadas las teclas de volumen. Se ha desactivado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Suelta las teclas de volumen. Para activar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, mantén pulsadas las dos teclas de volumen de nuevo durante 3 segundos."</string>
@@ -1799,6 +1798,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"¿Cambiar al micrófono del teléfono?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"¿Cambiar al micrófono del audífono?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Para mejorar el sonido o si la batería de tu audífono está baja. Esta opción solo cambia el micrófono durante la llamada."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Puedes usar el micrófono de tu audífono para hacer llamadas en manos libres. Esta opción solo cambia el micrófono durante la llamada."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Cambiar"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Ajustes"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Cerrando la sesión de <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2455,6 +2460,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Contenido de la aplicación oculto en pantalla compartida por seguridad"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Conectado automáticamente al satélite"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Puedes enviar y recibir mensajes sin una red móvil o Wi-Fi"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"¿Usar mensajes por satélite?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Envía y recibe mensajes sin una red móvil ni Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Abre Mensajes"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 3e3e5db60163..cf875408ed14 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Mobiilsidevõrguga ei saa ühendust"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Proovige eelistatud võrku vahetada. Puudutage muutmiseks."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Hädaabikõned pole saadaval"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Ära enam kuva"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Hädaabikõnede jaoks on vajalik mobiilsidevõrk"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Teatised"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Kõnede suunamine"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Võrguteavitused"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Võrk on saadaval"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN-i olek"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Aeg ja ajavööndid"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Teie IT-administraatori teatised"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Teatised"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Poedemo"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Rakendus töötab"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Rakendused kasutavad akutoidet"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Suurendus"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Kuuldeseade"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Juurdepääsetavuse kasutus"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Ekraan"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> kasutab akutoidet"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Laadi alla rakendus"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Uus SIM-kaart on sisestatud"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Puudutage seadistamiseks"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Teie ajavöönd muutus"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Olete praegu ajavööndis <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Kellaaja määramine"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Kuupäeva määramine"</string>
<string name="date_time_set" msgid="4603445265164486816">"Määra"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Ühekäerežiim"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Eriti tume"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Kuuldeseadmed"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Ühendus katkestatud"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Ühendatud"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktiivne"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Laadimine"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Helitugevuse klahve hoiti all. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> lülitati sisse."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Helitugevuse klahve hoiti all. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> lülitati välja."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Vabastage helitugevuse klahvid. Teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> sisselülitamiseks vajutage uuesti mõlemat helitugevuse klahvi ja hoidke neid 3 sekundit all."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Kas vahetada telefoni mikrofonile?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Kas vahetada kuuldeaparaadi mikrofonile?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Parema heli tagamiseks või siis, kui tele kuuldeaparaadi aku on tühi. See vahetab teie mikrofoni ainult kõne ajal."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Saate kasutada oma kuuldeaparaadi mikrofon vabakäerežiimis helistamiseks. See vahetab teie mikrofoni ainult kõne ajal."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Vaheta"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Seaded"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Kasutaja <xliff:g id="NAME">%1$s</xliff:g> väljalogimine …"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Rakenduse sisu on ekraani jagamisel turvalisuse huvides peidetud"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Satelliidiga loodi automaatselt ühendus"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Teil on võimalik sõnumeid saata ja vastu võtta ilma mobiilside- ja WiFi-võrguta"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Kas soovite kasutada satelliidipõhist sõnumsidet?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Sõnumite saatmine ja vastuvõtmine ilma mobiilside- või WiFi-võrguta"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Ava rakendus Messages"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 2f477f3b2010..8e689594ea2a 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Ezin da konektatu sare mugikorrera"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Aldatu sare hobetsia. Sakatu aldatzeko."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Ezin da egin larrialdi-deirik"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Ez erakutsi berriro"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Sare mugikorrera konektatuta egon behar duzu larrialdi-deiak egin ahal izateko"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertak"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Dei-desbideratzea"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Sarearen alertak"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Sare bat erabilgarri dago"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN egoera"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Ordua eta ordu-zonak"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"IKT saileko administratzaileak bidalitako alertak"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Alertak"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Saltzaileentzako demoa"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Aplikazio bat abian da"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Bateria kontsumitzen ari diren aplikazioak"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Lupa"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Entzumen-gailua"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Erabilerraztasun-hobespenak"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Pantaila"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> ari da bateria erabiltzen"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Deskargatu aplikazioa"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"SIM berria sartu da"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Sakatu konfiguratzeko"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Ordu-zonaz aldatu zara"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Oraingo ordu-zona: <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Ezarri ordua"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Ezarri data"</string>
<string name="date_time_set" msgid="4603445265164486816">"Ezarri"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Esku bakarreko modua"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Are ilunago"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Entzumen-gailuak"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Deskonektatuta"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Konektatuta"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktibo"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Kargatzen"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Bolumen-botoiak sakatuta eduki direnez, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktibatu egin da."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Bolumen-botoiak sakatuta eduki direnez, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desaktibatu egin da."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Askatu bolumen-botoiak. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktibatzeko, eduki sakatuta berriro bi bolumen-botoiak hiru segundoz."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Telefonoaren mikrofonora aldatu nahi duzu?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Audifonoaren mikrofonora aldatu nahi duzu?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Audioaren kalitatea hobetzeko edo audifonoak bateria gutxi badu. Deirako soilik aldatzen da mikrofonoa."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Audifonoaren mikrofonoa erabil dezakezu esku libreko deiak egiteko. Deirako soilik aldatzen da mikrofonoa."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Aldatu"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Ezarpenak"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzailearen saioa amaitzen…"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Aplikazioko edukia ezkutatu egin da pantaila partekatzeko eginbidetik, segurtasuna bermatzeko"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Automatikoki konektatu da satelitera"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Mezuak bidal eta jaso ditzakezu sare mugikorrik edo wifi-sarerik gabe"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Satelite bidezko mezularitza erabili nahi duzu?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Bidali eta jaso mezuak sare mugikorrik edo wifi-sarerik gabe"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Ireki Mezuak"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index d8fdff631b7d..9f2c7bb43c69 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"شبکه تلفن همراه دردسترس نیست"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"تغییر شبکه ترجیحی را امتحان کنید. برای تغییر، تک‌ضرب بزنید."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"تماس اضطراری امکان‌پذیر نیست"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"دیگر نشان داده نشود"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"برای برقراری تماس اضطراری به شبکه تلفن همراه نیاز دارید"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"هشدارها"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"بازارسال تماس"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"هشدارهای شبکه"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"شبکه دردسترس است"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"‏وضعیت VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"زمان و منطقه‌های زمانی"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"هشدارهایی از سرپرست فناوری اطلاعات"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"هشدارها"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"نمونه برای خرده‌فروشان"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"برنامه درحال اجرا"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"برنامه‌های مصرف‌کننده باتری"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"درشت‌نمایی"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"سمعک"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"کاربرد دسترس‌پذیری"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"نمایشگر"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> درحال استفاده کردن از باتری است"</string>
@@ -1215,7 +1216,7 @@
<string name="editTextMenuTitle" msgid="857666911134482176">"کنش‌های متنی"</string>
<string name="error_handwriting_unsupported" msgid="7809438534946014050">"در این فیلد از دست‌نویسی پشتیبانی نمی‌شود"</string>
<string name="error_handwriting_unsupported_password" msgid="5095401146106891087">"در فیلدهای گذرواژه از دست‌نویسی پشتیبانی نمی‌شود"</string>
- <string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"برگشت"</string>
+ <string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"برگشتن"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"تغییر روش ورودی"</string>
<string name="input_method_ime_switch_long_click_action_desc" msgid="3161942124116646998">"باز کردن انتخابگر روش ورودی"</string>
<string name="input_method_switcher_settings_button" msgid="5609835654697108485">"تنظیمات"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"بارگیری برنامه"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"سیم‌کارت جدید جاگذاری شد"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"برای تنظیم آن تک‌ضرب بزنید"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"منطقه زمانی‌تان تغییر کرد"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"درحال‌حاضر در <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> ‏(<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) هستید"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"تنظیم زمان"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"تاریخ تنظیم"</string>
<string name="date_time_set" msgid="4603445265164486816">"تنظیم"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"حالت یک‌دستی"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"بسیار کم‌نور"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"دستگاه‌های کمک‌شنوایی"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"متصل نیست"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"متصل"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"فعال"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"درحال بار کردن"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"کلیدهای میزان صدا پایین نگه داشته شد. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> روشن شد."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"کلیدهای میزان صدا پایین نگه داشته شد. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> خاموش شد."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"کلیدهای میزان صدا را رها کنید. برای روشن کردن <xliff:g id="SERVICE_NAME">%1$s</xliff:g>، هر دو کلید میزان صدا را مجدداً به‌مدت ۳ ثانیه فشار دهید و نگه دارید."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"از میکروفون تلفن استفاده شود؟"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"از میکروفون سمعک استفاده شود؟"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"برای صدای بهتر یا اگر شارژ باتری سمعک شما کم باشد. این کار فقط درطول تماس میکروفون شما را عوض می‌کند."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"برای تماس دست‌آزاد می‌توانید از میکروفون سمعک خود استفاده کنید. این کار فقط درطول تماس میکروفون شما را عوض می‌کند."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"عوض کردن"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"تنظیمات"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"در حال خروج از سیستم <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2029,7 +2034,7 @@
<string name="search_language_hint" msgid="7004225294308793583">"نام زبان را تایپ کنید"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"پیشنهادی"</string>
<string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"پیشنهادی"</string>
- <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"زبان‌های پیشنهادی"</string>
+ <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"زبان‌های پیشنهادشده"</string>
<string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"مناطق پیشنهادی"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"همه زبان‌ها"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"همه منطقه‌ها"</string>
@@ -2454,6 +2459,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"از «پیام‌رسانی ماهواره‌ای» استفاده شود؟"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"‏ارسال و دریافت پیام بدون شبکه تلفن همراه یا Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"باز کردن «پیام‌نگار»"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 9f88732cd7b4..0b65ee2c5403 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Mobiiliverkkoon ei saada yhteyttä"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Kokeile vaihtaa ensisijaista verkkoa. Vaihda se napauttamalla."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Hätäpuhelut eivät ole käytettävissä"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Älä näytä uudelleen"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Hätäpuhelu edellyttää mobiiliverkkoa"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Ilmoitukset"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Soitonsiirto"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Verkkoilmoitukset"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Verkko käytettävissä"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN-tila"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Aika ja aikavyöhykkeet"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Ilmoitukset IT-järjestelmänvalvojalta"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Ilmoitukset"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Esittelytila"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Sovellus käynnissä"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Akkua kuluttavat sovellukset"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Suurennus"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Kuulolaite"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Esteetön käyttö"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Näyttö"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> käyttää akkua."</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Lataa sovellus"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Uusi SIM-kortti asetettu"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Määritä se napauttamalla"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Aikavyöhykkeesi on muuttunut"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Olet nyt aikavyöhykkeellä <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Aseta aika"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Aseta päivämäärä"</string>
<string name="date_time_set" msgid="4603445265164486816">"Aseta"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Yhden käden moodi"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Erittäin himmeä"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Kuulolaitteet"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Yhteys katkaistu"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Yhdistetty"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktiivinen"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Ladataan"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Äänenvoimakkuuspainikkeita painettiin pitkään. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> laitettiin päälle."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Äänenvoimakkuuspainikkeita painettiin pitkään. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> laitettiin pois päältä."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Vapauta äänenvoimakkuuspainikkeet. Laita <xliff:g id="SERVICE_NAME">%1$s</xliff:g> päälle painamalla äänenvoimakkuuspainikkeita uudelleen kolmen sekunnin ajan."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Vaihdetaanko puhelimen mikrofoniin?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Vaihdetaanko kuulolaitteen mikrofoniin?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Jos haluat paremman äänen tai kuulolaitteen akku on vähissä. Tämä vaihtaa mikrofonia vain puhelun ajaksi."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Voit soittaa ääniohjatusti kuulolaitteen mikrofonin avulla. Tämä vaihtaa mikrofonia vain puhelun ajaksi."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Vaihda"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Asetukset"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> kirjautuu ulos…"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sovelluksen sisältö piilotettu näytön jakamiselta turvallisuussyistä"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Yhdistetty automaattisesti satelliittiin"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Voit lähettää ja vastaanottaa viestejä ilman mobiili‑ tai Wi-Fi-verkkoa"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Käytetäänkö satelliittiviestintää?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Lähetä ja vastaanota viestejä ilman mobiili- tai Wi-Fi-verkkoa"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Avaa Messages"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index c535bc078b4d..e9331bb826c4 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -88,8 +88,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Impossible de joindre le réseau cellulaire"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Essayez de changer de réseau préféré. Touchez l\'écran pour changer."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Le service d\'appel d\'urgence n\'est pas accessible"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Ne plus afficher"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Les appels d\'urgence nécessitent un réseau cellulaire"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertes"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Transfert d\'appel"</string>
@@ -304,6 +303,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Alertes réseau"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Réseau accessible"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"État du RPV"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Heure et fuseaux horaires"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Alertes de votre administrateur informatique"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Alertes"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Démo en magasin"</string>
@@ -311,6 +311,7 @@
<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_hearing_device" msgid="7816963856388758952">"Appareil auditif"</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>
@@ -1408,6 +1409,8 @@
<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_zone_change_notification_title" msgid="5232503069219193218">"Vous avez changé de fuseau horaire"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Voici le fuseau horaire dans lequel vous vous trouvez maintenant : <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Définir l\'heure"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Définir la date"</string>
<string name="date_time_set" msgid="4603445265164486816">"Paramètres"</string>
@@ -1781,14 +1784,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mode Une main"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Très sombre"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Appareils auditifs"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Déconnecté"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connecté"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Actif"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Chargement en cours…"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Touches de volume maintenues enfoncées. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> activé."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Touches de volume maintenues enfoncées. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> désactivé."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Relâchez les touches de volume. Pour activer <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, maintenez les deux touches de volume enfoncées pendant 3 secondes."</string>
@@ -1799,6 +1798,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Passer au micro du téléphone?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Passer au micro pour la prothèse auditive?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Pour profiter d\'un meilleur son ou si la pile de votre prothèse auditive est faible. Cette option ne change votre micro que pendant l\'appel."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Vous pouvez utiliser votre microphone pour prothèse auditive pour faire des appels en mode mains libres. Cette option ne change votre micro que pendant l\'appel."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Changer"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Paramètres"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Déconnexion de <xliff:g id="NAME">%1$s</xliff:g> en cours..."</string>
@@ -2455,6 +2460,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Le contenu de l\'appli est masqué du Partage d\'écran par mesure de sécurité"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Connecté au satellite automatiquement"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Vous pouvez envoyer et recevoir des messages sans avoir recours à un appareil mobile ou à un réseau Wi-Fi"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Utiliser la messagerie par satellite?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Envoyez et recevez des messages sans réseau cellulaire ou Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Ouvrir Messages"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index aa45f91f0975..cbcc961f309a 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -88,8 +88,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Impossible d\'accéder au réseau mobile"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Essayez de changer le réseau préféré. Appuyez pour le modifier."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Appels d\'urgence non disponibles"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Ne plus afficher"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Les appels d\'urgence requièrent un réseau mobile"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertes"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Transfert d\'appel"</string>
@@ -304,6 +303,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Alertes réseau"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Réseau disponible"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"État du VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Heure et fuseaux horaires"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Alertes de votre administrateur informatique"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Alertes"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Démonstration en magasin"</string>
@@ -311,6 +311,7 @@
<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 utilisant la batterie"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Agrandissement"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Appareil auditif"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Utilisation de l\'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> utilise la batterie"</string>
@@ -1408,6 +1409,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Télécharger l\'application"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Nouvelle carte SIM insérée"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Appuyez ici pour effectuer la configuration."</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Votre fuseau horaire a changé"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Vous êtes maintenant sur le fuseau horaire <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Définir l\'heure"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Définir la date"</string>
<string name="date_time_set" msgid="4603445265164486816">"Définir"</string>
@@ -1781,14 +1784,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mode une main"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Luminosité ultra-réduite"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Appareils auditifs"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Déconnecté"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connecté"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Actif"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Chargement"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Touches de volume appuyées de manière prolongée. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> activé."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Touches de volume appuyées de manière prolongée. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> désactivé."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Relâchez les boutons de volume. Pour activer <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, appuyez de nouveau sur les deux boutons de volume pendant trois secondes."</string>
@@ -1799,6 +1798,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Passer au micro du téléphone ?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Passer au micro de l\'appareil auditif ?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Pour améliorer le son ou si la batterie de votre appareil auditif est faible. Cette option change uniquement le micro pendant l\'appel."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Vous pouvez utiliser le micro de votre appareil auditif pour passer des appels en mode mains-libres. Cette option change uniquement le micro pendant l\'appel."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Changer"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Paramètres"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Déconnexion de <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2455,6 +2460,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Le contenu de l\'appli est masqué lors du partage d\'écran par mesure de sécurité"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Connecté automatiquement au réseau satellite"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Vous pouvez envoyer et recevoir des messages sans connexion au réseau mobile ou Wi-Fi"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Utiliser la messagerie par satellite ?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Envoyer et recevoir des messages sans réseau mobile ou Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Ouvrir Messages"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index a1016b688282..25aac2cd0615 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Non se puido conectar coa rede de telefonía móbil"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Proba a cambiar a rede preferida. Toca para cambiar."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"As chamadas de emerxencia non están dispoñibles"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Non mostrar de novo"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"As chamadas de emerxencia precisan unha rede de telefonía móbil"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertas"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Desvío de chamadas"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Alertas de rede"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"A rede está dispoñible"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Estado da VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Hora e fusos horarios"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Alertas do teu administrador de TI"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Alertas"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demostración comercial"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Estase executando a aplicación"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Aplicacións que consomen batería"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Ampliación"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Dispositivo auditivo"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Uso de accesibilidade"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Pantalla"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"A aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> está consumindo batería"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Descargar aplicación"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Introduciuse unha nova SIM"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Tocar para configurar"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Cambiaches de fuso horario"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Estás en <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Configurar hora"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Establecer data"</string>
<string name="date_time_set" msgid="4603445265164486816">"Configurar"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo dunha soa man"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Atenuación extra"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Dispositivos auditivos"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desconectado"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Conectado"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Activo"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Cargando"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume premidas. Activouse o servizo <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume premidas. Desactivouse <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Solta as teclas de volume. Para activar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, mantenas premidas de novo durante 3 segundos."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Queres cambiar ao micrófono do teléfono?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Queres cambiar ao micrófono do audiófono?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Para mellorar o son ou se o audiófono ten pouca batería. Esta acción só cambia o micrófono durante a chamada."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Podes usar o micrófono do audiófono para facer chamadas coas mans libres. Esta acción só cambia o micrófono durante a chamada."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Cambiar"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Configuració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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Pechando sesión de <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Por seguranza, ocultouse o contido da aplicación na pantalla compartida"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Conexión automática ao satélite"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Podes enviar e recibir mensaxes sen unha rede de telefonía móbil ou wifi"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Queres usar a mensaxaría por satélite?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Envía e recibe mensaxes sen ter acceso a redes de telefonía móbil ou wifi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir Mensaxes"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 046939b3bf3c..c38768dc3e30 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"મોબાઇલ નેટવર્ક સુધી પહોંચી શકાતું નથી"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"પસંદગીનું નેટવર્ક બદલવાનો પ્રયાસ કરો. બદલવા માટે ટૅપ કરો."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"કટોકટીની કૉલિંગ સેવા અનુપલબ્ધ"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"ફરી બતાવશો નહીં"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"ઇમર્જન્સી કૉલ માટે મોબાઇલ નેટવર્કની આવશ્યકતા છે"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"અલર્ટ"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"કૉલ ફૉર્વર્ડિંગ"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"નેટવર્ક ચેતવણીઓ"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"નેટવર્ક ઉપલબ્ધ છે"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN સ્થિતિ"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"સમય અને સમય ઝોન"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"તમારા IT વ્યવસ્થાપક તરફથી અલર્ટ"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"અલર્ટ"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"રિટેલ ડેમો"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"ઍપ ચાલી રહ્યું છે"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"ઍપ બૅટરીનો વપરાશ કરી રહ્યાં છે"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"મોટું કરવાની સુવિધા"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"સાંભળવામાં મદદ આપતા ડિવાઇસ"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"ઍક્સેસિબિલિટી વપરાશ"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"ડિસ્પ્લે"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> બૅટરીનો ઉપયોગ કરી રહ્યું છે"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"ઍપ ડાઉનલોડ કરો"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"નવું સિમ દાખલ કર્યું"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"તેને સેટ કરવા માટે ટૅપ કરો"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"તમારો સમય ઝોન બદલાયો છે"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"તમે <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)માં છો"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"સમય સેટ કરો"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"તારીખ સેટ કરો"</string>
<string name="date_time_set" msgid="4603445265164486816">"સેટ કરો"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"એક-હાથે વાપરો મોડ"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"એક્સ્ટ્રા ડિમ"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"સાંભળવામાં સહાય કરતા ડિવાઇસ"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ડિસ્કનેક્ટેડ છે"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"કનેક્ટેડ છે"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"સક્રિય"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"લોડ કરી રહ્યાં છીએ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"વૉલ્યૂમ કી દબાવી રાખો. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ચાલુ કરી."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"વૉલ્યૂમ કી દબાવી રાખો. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> બંધ કરી."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"વૉલ્યૂમ કી છોડી દો. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ને ચાલુ કરવા માટે, 3 સેકન્ડ માટે બન્ને વૉલ્યૂમ કીને ફરીથી દબાવી રાખો."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"ફોનના માઇક પર સ્વિચ કરીએ?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"સાંભળવામાં મદદ આપતા યંત્રના માઇક પર સ્વિચ કરીએ?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"બહેતર સાઉન્ડ માટે અથવા જો સાંભળવામાં મદદ આપતા તમારા યંત્રની બૅટરી ઓછી હોય. કૉલ દરમિયાન આ ફક્ત તમારા માઇકને સ્વિચ કરે છે."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"તમે હાથના ઉપયોગ વિના કૉલ કરવા માટે સાંભળવામાં મદદ આપતા તમારા યંત્રના માઇક્રોફોનનો ઉપયોગ કરી શકો છો. કૉલ દરમિયાન આ ફક્ત તમારા માઇકને સ્વિચ કરે છે."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"સ્વિચ કરો"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"સેટિંગ"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> લોગ આઉટ થઈ રહ્યાં છે…"</string>
@@ -2454,6 +2459,8 @@
<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">"તમે મોબાઇલ અથવા વાઇ-ફાઇ નેટવર્ક વિના મેસેજ મોકલી અને પ્રાપ્ત કરી શકો છો"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"શું સૅટલાઇટ મેસેજિંગનો ઉપયોગ કરીએ?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"મોબાઇલ કે વાઇ-ફાઇ નેટવર્ક વિના મેસેજ મોકલો અને મેળવો"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ખોલો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 7717d0276916..6199c806d5e2 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"मोबाइल नेटवर्क से कनेक्ट नहीं किया जा सका"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"पसंदीदा नेटवर्क बदलकर देखें. बदलने के लिए टैप करें."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"आपातकालीन कॉल करने की सुविधा उपलब्ध नहीं है"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"दोबारा न दिखाएं"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"आपातकालीन कॉल के लिए मोबाइल नेटवर्क ज़रूरी है"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"सूचनाएं"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"कॉल को दूसरे नंबर पर भेजना"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"नेटवर्क संबंधी सूचनाएं"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"नेटवर्क उपलब्ध है"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN की स्थिति"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"टाइम और टाइम ज़ोन"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"आपके आईटी एडमिन से मिली चेतावनियां"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"सूचनाएं"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"खुदरा डेमो"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"ऐप अभी इस्तेमाल हो रहा है"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"बैटरी की खपत करने वाले ऐप"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"ज़ूम करने की सुविधा"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"कान की मशीन"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"सुलभता सुविधाओं का इस्तेमाल"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"डिसप्ले"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> बैटरी का इस्तेमाल कर रहा है"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"ऐप्लिकेशन डाउनलोड करें"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"नई SIM डाली गई"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"इसे सेट करने के लिए टैप करें"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"आपका टाइम ज़ोन बदल गया है"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"अब आप <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) में हैं"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"समय सेट करें"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"तारीख सेट करें"</string>
<string name="date_time_set" msgid="4603445265164486816">"सेट करें"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"वन-हैंडेड मोड"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"स्क्रीन की रोशनी को सामान्य लेवल से और कम करने की सुविधा"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"कान की मशीन"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"डिसकनेक्ट हो गया"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"कनेक्ट हो गया"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"चालू है"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"लोड हो रहा है"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"आवाज़ कम-ज़्यादा करने वाले दोनों बटन दबाकर रखें. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को चालू कर दिया गया."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"आवाज़ कम-ज़्यादा करने वाले दोनों बटन दबाकर रखें. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को बंद कर दिया गया."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"आवाज़ बटन को छोड़ें. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> की सुविधा चालू करने के लिए, आवाज़ वाले दोनों बटन तीन सेकंड तक दबाकर रखें."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"क्या आपको फ़ोन के माइक्रोफ़ोन पर स्विच करना है?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"क्या आपको कान की मशीन के माइक पर स्विच करना है?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"बेहतर आवाज़ के लिए या कान की मशीन की बैटरी कम होने पर. यह सिर्फ़ कॉल के दौरान आपका माइक चालू करता है."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"बोलकर कॉल का जवाब देने के लिए, \'कान की मशीन का माइक्रोफ़ोन\' इस्तेमाल किया जा सकता है. इससे, कॉल के दौरान सिर्फ़ आपका माइक चालू या बंद होता है."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"स्विच करें"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"सेटिंग"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> द्वारा प्रस्‍थान किया जा रहा है…"</string>
@@ -2454,6 +2459,7 @@
<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">"मोबाइल या वाई-फ़ाई नेटवर्क के बिना भी मैसेज भेजे और पाए जा सकते हैं"</string>
+ <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"सैटलाइट के ज़रिए मैसेज भेजें और पाएं. साथ ही, सीमित डेटा का इस्तेमाल करें"</string>
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"क्या आपको सैटलाइट की मदद से मैसेज भेजना है?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"मोबाइल या वाई-फ़ाई नेटवर्क के बिना मैसेज भेजें और पाएं"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ऐप्लिकेशन खोलें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 118b53928b61..5b3dc7c86658 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -88,8 +88,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Mobilna mreža nije dostupna"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Pokušajte promijeniti preferiranu mrežu. Dodirnite da biste je promijenili."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Hitni pozivi nisu dostupni"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Ne prikazuj ponovo"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Za hitne pozive potrebna je mobilna mreža"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Upozorenja"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Preusmjeravanje poziva"</string>
@@ -304,6 +303,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Mrežna upozorenja"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Mreža je dostupna"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Status VPN-a"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Vrijeme i vremenske zone"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Upozorenja IT administratora"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Upozorenja"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Prodajni demo-način"</string>
@@ -311,6 +311,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Izvodi se aplikacija"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Aplikacije troše bateriju"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Povećavanje"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Slušno pomagalo"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Upotreba pristupačnosti"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Zaslon"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> koristi bateriju"</string>
@@ -1408,6 +1409,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Preuzmite aplikaciju"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Umetnuta je nova SIM kartica"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Dodirnite da biste je postavili"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Vaša je vremenska zona promijenjena"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Sada ste u vremenskoj zoni <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Postavljanje vremena"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Postavi datum"</string>
<string name="date_time_set" msgid="4603445265164486816">"Postavi"</string>
@@ -1781,14 +1784,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Način rada jednom rukom"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Još tamnije"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Slušna pomagala"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Nije povezano"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Povezano"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktivno"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Učitavanje"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tipke za glasnoću. Uključila se usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tipke za glasnoću. Isključila se usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Pustite tipke za glasnoću. Da biste uključili uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, ponovo pritisnite i zadržite obje tipke za glasnoću tri sekunde."</string>
@@ -1799,6 +1798,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Želite li se prebaciti na mikrofon telefona?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Želite li se prebaciti na mikrofon slušnog pomagala?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Za bolji zvuk ili ako je razina baterije slušnog pomagala niska. Time se mikrofon prebacuje samo tijekom poziva."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Mikrofon slušnog pomagala možete koristiti za pozivanje bez upotrebe ruku. Time se mikrofon prebacuje samo tijekom poziva."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Prebaci"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Postavke"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Odjavljivanje korisnika <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2455,6 +2460,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije sakriven je od dijeljenja zaslona radi sigurnosti"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Automatski povezano sa satelitom"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Možete slati i primati poruke bez mobilne mreže ili Wi-Fi mreže"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Želite li slati poruke putem satelita?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Šaljite i primajte poruke kad nije dostupna mobilna ili Wi-Fi mreža"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvori Poruke"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 09f162eba32e..117509955341 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"A mobilhálózat nem érhető el"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Próbálja meg módosítani a preferált hálózatot. Koppintson a módosításhoz."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Segélyhívás nem lehetséges"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Ne jelenjen meg újra"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"A segélyhíváshoz mobilhálózatra van szükség"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Értesítések"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Hívásátirányítás"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Hálózati értesítések"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Van elérhető hálózat"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN-állapot"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Idő és időzónák"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Értesítések a rendszergazdától"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Értesítések"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Kiskereskedelmi bemutató"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Jelenleg futó alkalmazás"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Akkumulátort használó alkalmazások"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Nagyítás"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Hallókészülék"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Kisegítő lehetőségek használata"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Kijelző"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás használja az akkumulátort"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Alkalmazás letöltése"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Új SIM behelyezve"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Koppintson rá a beállításhoz"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Az időzóna megváltozott"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Mostani időzóna: <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Idő beállítása"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Dátum beállítása"</string>
<string name="date_time_set" msgid="4603445265164486816">"Beállítás"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Egykezes mód"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extrasötét"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hallásjavító eszközök"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Leválasztva"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Csatlakozva"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktív"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Betöltés"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Nyomva tartotta a hangerőgombokat. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> bekapcsolva."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Nyomva tartotta a hangerőgombokat. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kikapcsolva."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Engedje fel a hangerőszabályzó gombokat. A(z) <xliff:g id="SERVICE_NAME">%1$s</xliff:g> bekapcsolásához tartsa újra lenyomva a hangerőszabályzó gombokat három másodpercig."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Átvált a telefon mikrofonjára?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Átvált a hallókészülék mikrofonjára?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"A jobb hangzás érdekében, vagy ha a hallókészülék akkumulátora merülőben van. Csak a mikrofont kapcsolja át hívás közben."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Használhatja hallókészüléke mikrofonját a szabadkezes hívásokhoz. Csak a mikrofont kapcsolja át hívás közben."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Váltás"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Beállítások"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> kijelentkeztetése folyamatban van…"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Apptartalom elrejtve a megosztástól a biztonság érdekében"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Automatikusan csatlakozva a műholdhoz"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Küldhet és fogadhat üzeneteket mobil- és Wi-Fi-hálózat nélkül is"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Műholdas üzenetváltást szeretne használni?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Küldhet és fogadhat üzeneteket mobil- és Wi-Fi-hálózat nélkül is"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"A Messages megnyitása"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 7a821a695edc..c89544823314 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Չհաջողվեց միանալ բջջային ցանցին"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Փորձեք այլ ցանցի միանալ: Հպեք՝ նախընտրած ցանցը փոխելու համար:"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Շտապ կանչերը հասանելի չեն"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Այլևս ցույց չտալ"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Շտապ կանչերի համար բջջային ցանց է անհրաժեշտ"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Ծանուցումներ"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Զանգի վերահասցեավորում"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Ցանցային զգուշացումներ"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Ցանցը հասանելի է"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN կարգավիճակ"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Ժամ և ժամային գոտի"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Ծանուցումներ ձեր ՏՏ ադմինիստրատորից"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Ծանուցումներ"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Խանութի ցուցադրական ռեժիմ"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Հավելվածն աշխատում է"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Մարտկոցի լիցքը ծախսող հավելվածներ"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Խոշորացում"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Լսողական սարք"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Հատուկ գործառույթների օգտագործում"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Էկրան"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"«<xliff:g id="APP_NAME">%1$s</xliff:g>» հավելվածը ծախսում է մարտկոցի լիցքը"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Ներբեռնել հավելվածը"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Տեղադրվել է նոր SIM քարտ"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Հպեք՝ կարգավորելու համար"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Ձեր ժամային գոտին փոխվեց"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Դուք այժմ <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) ժամային գոտում եք"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Սահմանել ժամը"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Սահմանել ամսաթիվը"</string>
<string name="date_time_set" msgid="4603445265164486816">"Սահմանել"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Մեկ ձեռքի ռեժիմ"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Հավելյալ խամրեցում"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Լսողական սարքեր"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Անջատված է"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Միացված է"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Ակտիվ է"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Բեռնում"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ձայնի կարգավորման կոճակները սեղմվեցին։ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունը միացավ։"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ձայնի կարգավորման կոճակները սեղմվեցին։ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունն անջատվեց։"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Բաց թողեք ձայնի ուժգնության կոճակները։ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունը միացնելու համար սեղմեք և 3 վայրկյան պահեք ձայնի ուժգնության երկու կոճակը։"</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Անցնե՞լ հեռախոսի խոսափողին"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Անցնե՞լ լսողական սարքի խոսափողին"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Խոսափողը կարող եք օգտագործել, եթե ձայնի որակը ցածր է, կամ լսողական սարքի մարտկոցի լիցքը քիչ է։ Դուք կանցնեք խոսափողին միայն զանգի ընթացքում։"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Լսողական սարքի խոսափողը կարող եք օգտագործել ձայնային կառավարման համար։ Դուք կանցնեք խոսափողին միայն զանգի ընթացքում։"</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Անցնել"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Կարգավորումներ"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Ելք <xliff:g id="NAME">%1$s</xliff:g>-ից…"</string>
@@ -2454,6 +2459,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Օգտագործե՞լ արբանյակային հաղորդագրումը"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Ուղարկեք և ստացեք հաղորդագրություններ առանց բջջային կամ Wi-Fi ցանցի"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Բացել Messages-ը"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 3c0deb7c62ce..26a79e0b53a9 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Tidak dapat menjangkau jaringan seluler"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Coba ubah jaringan pilihan. Ketuk untuk mengubah."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Panggilan darurat tidak tersedia"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Jangan Tampilkan Lagi"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Panggilan darurat memerlukan jaringan seluler"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Notifikasi"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Penerusan panggilan"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Notifikasi jaringan"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Jaringan tersedia"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Status VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Waktu dan zona waktu"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Notifikasi dari admin IT"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Notifikasi"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demo promo"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Aplikasi berjalan"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Aplikasi yang menggunakan baterai"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Pembesaran"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Alat bantu dengar"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Penggunaan aksesibilitas"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Layar"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang menggunakan baterai"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Download aplikasi"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"SIM baru dimasukkan"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Ketuk untuk menyiapkan"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Zona waktu Anda diubah"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Anda sekarang berada di <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Setel waktu"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Setel tanggal"</string>
<string name="date_time_set" msgid="4603445265164486816">"Setel"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mode satu tangan"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra redup"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Alat bantu dengar"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Tidak terhubung"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Terhubung"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktif"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Memuat"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tombol volume ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> diaktifkan."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tombol volume ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dinonaktifkan."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Lepaskan tombol volume. Untuk mengaktifkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, tekan kedua tombol volume lagi selama 3 detik."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Beralih ke mikrofon ponsel?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Beralih ke mikrofon alat bantu dengar?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Untuk mendapatkan kualitas suara yang lebih baik atau jika daya baterai alat bantu dengar Anda lemah. Tindakan ini hanya akan mengalihkan mikrofon Anda selama panggilan."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Anda dapat menggunakan mikrofon alat bantu dengar untuk melakukan panggilan handsfree. Tindakan ini hanya akan mengalihkan mikrofon Anda selama panggilan."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Alihkan"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Setelan"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Mengeluarkan <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Konten aplikasi disembunyikan dari berbagi layar karena alasan keamanan"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Menghubungkan otomatis ke satelit"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Anda dapat mengirim dan menerima pesan tanpa jaringan seluler atau Wi-Fi"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Gunakan fitur pesan satelit?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Mengirim dan menerima pesan tanpa jaringan seluler atau Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Buka Message"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 6a3519134688..f6d043b170ed 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Ekki næst samband við farsímakerfi"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Prófaðu að velja annað símkerfi. Ýttu til að breyta."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Neyðarsímtöl eru ekki í boði"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Ekki birta aftur"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Neyðarsímtöl krefjast farsímakerfis"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Tilkynningar"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Símtalsflutningur"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Viðvaranir netkerfis"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Net í boði"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Staða VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Tími og tímabelti"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Tilkynningar frá kerfisstjóra"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Tilkynningar"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Kynningarútgáfa fyrir verslanir"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Forrit er í gangi"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Forrit sem nota rafhlöðuorku"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Stækkun"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Heyrnartæki"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Aðgengisnotkun"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Skjár"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> notar rafhlöðuorku"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Sækja forritið"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Nýtt SIM-kort sett í"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Ýttu til að setja það upp"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Tímabeltinu þínu var breytt"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Þú ert nú á <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Veldu tíma"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Veldu dagsetningu"</string>
<string name="date_time_set" msgid="4603445265164486816">"Velja"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Einhent stilling"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Mjög dökkt"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Heyrnartæki"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Aftengt"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Tengt"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Virkt"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Hleður"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Hljóðstyrkstökkum haldið inni. Kveikt á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Hljóðstyrkstökkum haldið inni. Slökkt á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Slepptu hljóðstyrkstökkunum. Til að kveikja á <xliff:g id="SERVICE_NAME">%1$s</xliff:g> skaltu halda báðum hljóðstyrkstökkunum aftur inni í 3 sekúndur."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Skipta yfir í hljóðnema símans?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Skipta yfir í hljóðnema heyrnartækis?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Fyrir betri hljómgæði eða ef lítil hleðsla er á heyrnartækinu. Aðeins verður skipt um hljóðnema á meðan á símtali stendur."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Þú getur notað hljóðnema heyrnartækisins þíns til að hringja eða svara símtölum handfrjálst. Aðeins verður skipt um hljóðnema á meðan á símtali stendur."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Skipta"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Stillingar"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Skráir <xliff:g id="NAME">%1$s</xliff:g> út…"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Efni forrits falið í skjádeilingu af öryggisástæðum"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Tengdist sjálfkrafa við gervihnött"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Þú getur sent og móttekið skilaboð án tengingar við farsímakerfi eða Wi-Fi"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Nota skilaboð í gegnum gervihnött?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Senda og fá skilaboð án tengingar við farsímakerfi eða Wi-Fi-net"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Opna Messages"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index db402c50205b..96075003f0b2 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -88,8 +88,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Impossibile raggiungere la rete mobile"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Prova a cambiare la rete preferita. Tocca per cambiare."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Chiamate di emergenza non disponibili"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Non mostrare più"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Per le chiamate di emergenza è necessaria una rete mobile"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Avvisi"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Deviazione chiamate"</string>
@@ -304,6 +303,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Avvisi di rete"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Rete disponibile"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Stato della VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Ora e fusi orari"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Avvisi dall\'amministratore IT"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Avvisi"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demo retail"</string>
@@ -311,6 +311,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"App in esecuzione"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"App che consumano la batteria"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Ingrandimento"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Protesi uditiva"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Utilizzo dell\'accessibilità"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Display"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> sta consumando la batteria"</string>
@@ -694,7 +695,7 @@
<string name="fingerprint_error_security_update_required" msgid="8440349108169661934">"Sensore temporaneamente disattivato"</string>
<string name="fingerprint_error_bad_calibration" msgid="6770614925736183528">"Impossibile usare il sensore di impronte digitali. Contatta un fornitore di servizi di riparazione."</string>
<string name="fingerprint_error_power_pressed" msgid="5479524500542129414">"Tasto di accensione premuto"</string>
- <string name="fingerprint_name_template" msgid="8941662088160289778">"Dito <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <string name="fingerprint_name_template" msgid="8941662088160289778">"Impronta <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usa l\'impronta"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usa l\'impronta o il blocco schermo"</string>
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utilizza la tua impronta per continuare"</string>
@@ -1408,6 +1409,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Scarica app"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Nuova SIM inserita"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Tocca per configurarla"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Il tuo fuso orario è cambiato"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Il tuo fuso orario attuale è <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Imposta ora"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Imposta data"</string>
<string name="date_time_set" msgid="4603445265164486816">"Imposta"</string>
@@ -1781,14 +1784,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modalità a una mano"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Attenuazione extra"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Protesi uditive"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Disconnesso"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connesso"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Attivo"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Caricamento in corso…"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tieni premuti i tasti del volume. Servizio <xliff:g id="SERVICE_NAME">%1$s</xliff:g> attivato."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tieni premuti i tasti del volume. Servizio <xliff:g id="SERVICE_NAME">%1$s</xliff:g> disattivato."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Rilascia i tasti del volume. Per attivare <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, tieni di nuovo premuti entrambi i tasti del volume per 3 secondi."</string>
@@ -1799,6 +1798,12 @@
<string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"La funzionalità si aprirà la prossima volta che utilizzerai questa scorciatoia. Scorri verso l\'alto con 2 dita dalla parte inferiore dello schermo e rilascia rapidamente."</string>
<string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"La funzionalità si aprirà la prossima volta che utilizzerai questa scorciatoia. Scorri verso l\'alto con 3 dita dalla parte inferiore dello schermo e rilascia rapidamente."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Ingrandimento"</string>
+ <string name="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Passare al microfono dello smartphone?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Passare al microfono dell\'apparecchio acustico?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Per una migliore resa audio o se la batteria dell\'apparecchio acustico è scarica. In questo modo, il microfono viene attivato solo durante la chiamata."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Puoi usare il microfono dell\'apparecchio acustico per le chiamate in vivavoce. In questo modo, il microfono viene attivato solo durante la chiamata."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Cambia"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Impostazioni"</string>
<string name="user_switched" msgid="7249833311585228097">"Utente corrente <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Passaggio a <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="7216437629179710359">"Disconnessione di <xliff:g id="NAME">%1$s</xliff:g> in corso…"</string>
@@ -2455,6 +2460,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Contenuti dell\'app nascosti dalla condivisione schermo per sicurezza"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Connessione automatica al satellite"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Puoi inviare e ricevere messaggi senza una rete mobile o Wi-Fi"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Utilizzare i messaggi via satellite?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Invia e ricevi messaggi senza una rete mobile o Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Apri Messaggi"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 503eb9747c96..d25cf01602e4 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -86,10 +86,9 @@
<string name="RestrictedStateContent" msgid="7693575344608618926">"הושבת באופן זמני על ידי הספק"</string>
<string name="RestrictedStateContentMsimTemplate" msgid="5228235722511044687">"‏השירות הושבת באופן זמני על ידי הספק עבור SIM‏ <xliff:g id="SIMNUMBER">%d</xliff:g>"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"לא ניתן להתחבר לרשת הסלולרית"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"אפשר לנסות לשנות את הרשת המועדפת. יש להקיש כדי לשנות אותה."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"אפשר לנסות לשנות את הרשת המועדפת. יש ללחוץ כדי לשנות אותה."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"שיחות חירום לא זמינות"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"לא להציג את זה שוב"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"כדי לבצע שיחות חירום, צריך להתחבר לרשת סלולרית"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"התראות"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"העברת שיחות"</string>
@@ -210,7 +209,7 @@
<string name="private_space_deleted_by_admin" msgid="1484365588862066939">"המרחב הפרטי הוסר"</string>
<string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"הארגון שלך לא מאפשר שימוש במרחבים פרטיים במכשיר המנוהל הזה."</string>
<string name="network_logging_notification_title" msgid="554983187553845004">"המכשיר מנוהל"</string>
- <string name="network_logging_notification_text" msgid="1327373071132562512">"הארגון שלך מנהל את המכשיר הזה והוא עשוי לנטר את התנועה ברשת. יש להקיש לקבלת פרטים."</string>
+ <string name="network_logging_notification_text" msgid="1327373071132562512">"הארגון שלך מנהל את המכשיר הזה והוא עשוי לנטר את התנועה ברשת. יש ללחוץ לקבלת פרטים."</string>
<string name="location_changed_notification_title" msgid="3620158742816699316">"לאפליקציות יש הרשאת גישה למיקום שלך"</string>
<string name="location_changed_notification_text" msgid="7158423339982706912">"‏יש לפנות למנהל ה-IT כדי לקבל מידע נוסף"</string>
<string name="geofencing_service" msgid="3826902410740315456">"שירות להגדרת גבולות וירטואליים"</string>
@@ -304,6 +303,8 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"התראות רשת"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"יש רשת זמינה"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"‏סטטוס ה-VPN"</string>
+ <!-- no translation found for notification_channel_system_time (1660313368058030441) -->
+ <skip />
<string name="notification_channel_device_admin" msgid="6384932669406095506">"‏התראות ממנהל ה-IT"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"התראות"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"הדגמה לקמעונאים"</string>
@@ -311,11 +312,13 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"אפליקציה פועלת"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"אפליקציות שמרוקנות את הסוללה"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"הגדלה"</string>
+ <!-- no translation found for notification_channel_accessibility_hearing_device (7816963856388758952) -->
+ <skip />
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"שימוש בנגישות"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"מסך"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> משתמשת בסוללה"</string>
<string name="foreground_service_apps_in_background" msgid="7340037176412387863">"<xliff:g id="NUMBER">%1$d</xliff:g> אפליקציות משתמשות בסוללה"</string>
- <string name="foreground_service_tap_for_details" msgid="9078123626015586751">"אפשר להקיש כדי לקבל פרטים על צריכה של נתונים וסוללה"</string>
+ <string name="foreground_service_tap_for_details" msgid="9078123626015586751">"אפשר ללחוץ כדי לקבל פרטים על צריכה של נתונים וסוללה"</string>
<string name="foreground_service_multiple_separator" msgid="5002287361849863168">"<xliff:g id="RIGHT_SIDE">%2$s</xliff:g>, <xliff:g id="LEFT_SIDE">%1$s</xliff:g>"</string>
<string name="safeMode" msgid="8974401416068943888">"מצב בטוח"</string>
<string name="android_system_label" msgid="5974767339591067210">"‏מערכת Android"</string>
@@ -356,13 +359,13 @@
<string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"אחזור תוכן של חלון"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"בדיקת התוכן של חלון שאיתו מתבצעת אינטראקציה."</string>
<string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"הפעלה של \'גילוי באמצעות מגע\'"</string>
- <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"פריטים שמקישים עליהם יוקראו בקול, וניתן לנווט במסך באמצעות תנועות."</string>
+ <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"פריטים שלוחצים עליהם יוקראו בקול, וניתן לנווט במסך באמצעות תנועות."</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"הצגת טקסט בזמן הקלדה"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"כולל נתונים אישיים כמו מספרי כרטיס אשראי וסיסמאות."</string>
<string name="capability_title_canControlMagnification" msgid="7701572187333415795">"שליטה בהגדלת התצוגה"</string>
<string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"קביעת המרחק מהתצוגה ומיקום התצוגה."</string>
<string name="capability_title_canPerformGestures" msgid="9106545062106728987">"ביצוע תנועות"</string>
- <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"יכול להקיש, להחליק, לעשות תנועת צביטה ולבצע תנועות אחרות."</string>
+ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"יכול ללחוץ, להחליק, לעשות תנועת צביטה ולבצע תנועות אחרות."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"תנועות של טביעות אצבעות"</string>
<string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"אפשרות לזהות תנועות בזמן נגיעה בחיישן טביעות האצבע של המכשיר."</string>
<string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"צילום המסך"</string>
@@ -693,7 +696,7 @@
<string name="fingerprint_error_hw_not_present" msgid="5898827259419366359">"במכשיר הזה אין חיישן טביעות אצבע"</string>
<string name="fingerprint_error_security_update_required" msgid="8440349108169661934">"החיישן מושבת באופן זמני"</string>
<string name="fingerprint_error_bad_calibration" msgid="6770614925736183528">"לא ניתן להשתמש בחיישן טביעות האצבע. צריך ליצור קשר עם ספק תיקונים."</string>
- <string name="fingerprint_error_power_pressed" msgid="5479524500542129414">"לחצן ההפעלה נלחץ"</string>
+ <string name="fingerprint_error_power_pressed" msgid="5479524500542129414">"כפתור ההפעלה נלחץ"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"אצבע <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"שימוש בטביעת אצבע"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"שימוש בטביעת אצבע או בנעילת מסך"</string>
@@ -709,7 +712,7 @@
<string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"אפשר להשתמש בביטול הנעילה בטביעת אצבע כשהפנים שלך לא מזוהות, למשל כשאין מספיק אור"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"פתיחה בזיהוי פנים"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"בעיה בפתיחה ע\"י זיהוי הפנים"</string>
- <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"יש להקיש כדי למחוק את התבנית לזיהוי הפנים, ואז להוסיף תבנית חדשה לזיהוי הפנים"</string>
+ <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"יש ללחוץ כדי למחוק את התבנית לזיהוי הפנים, ואז להוסיף תבנית חדשה לזיהוי הפנים"</string>
<string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"‏כדי להשתמש בתכונה \'פתיחה ע\"י זיהוי הפנים\', יש להפעיל את ה"<b>"גישה למצלמה"</b>" בהגדרות &gt; פרטיות"</string>
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"פתיחה בטביעת אצבע"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"לא ניתן להשתמש בחיישן טביעות האצבע"</string>
@@ -994,7 +997,7 @@
<string name="keyguard_password_enter_puk_code" msgid="3112256684547584093">"‏יש להקליד את קוד ה-PUK ואת קוד האימות החדש"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="2825313071899938305">"‏קוד PUK"</string>
<string name="keyguard_password_enter_pin_prompt" msgid="5505434724229581207">"קוד אימות חדש"</string>
- <string name="keyguard_password_entry_touch_hint" msgid="4032288032993261520"><font size="17">"יש להקיש כדי להקליד את הסיסמה"</font></string>
+ <string name="keyguard_password_entry_touch_hint" msgid="4032288032993261520"><font size="17">"יש ללחוץ כדי להקליד את הסיסמה"</font></string>
<string name="keyguard_password_enter_password_code" msgid="2751130557661643482">"יש להקליד סיסמה לביטול הנעילה"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7792964196473964340">"יש להקליד קוד אימות לביטול הנעילה"</string>
<string name="keyguard_password_wrong_pin_code" msgid="8583732939138432793">"קוד אימות שגוי"</string>
@@ -1106,7 +1109,7 @@
<string name="js_dialog_before_unload_negative_button" msgid="3873765747622415310">"להישאר בדף הזה"</string>
<string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nבטוח שברצונך לנווט אל מחוץ לדף הזה?"</string>
<string name="autofill_window_title" msgid="4379134104008111961">"מילוי אוטומטי באמצעות <xliff:g id="SERVICENAME">%1$s</xliff:g>"</string>
- <string name="permlab_setAlarm" msgid="1158001610254173567">"הגדרת התראה"</string>
+ <string name="permlab_setAlarm" msgid="1158001610254173567">"הגדרת שעון מעורר"</string>
<string name="permdesc_setAlarm" msgid="2185033720060109640">"מאפשרת לאפליקציה להגדיר התראה באפליקציה מותקנת של שעון מעורר. אפליקציות מסוימות של שעון מעורר אינן מיישמות את התכונה הזו."</string>
<string name="permlab_addVoicemail" msgid="4770245808840814471">"הוספה של דואר קולי"</string>
<string name="permdesc_addVoicemail" msgid="5470312139820074324">"מאפשרת לאפליקציה להוסיף הודעות לתיבת הדואר הקולי."</string>
@@ -1224,7 +1227,7 @@
<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_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>
@@ -1315,15 +1318,15 @@
<string name="android_preparing_apk" msgid="589736917792300956">"המערכת מכינה את <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
<string name="android_upgrading_starting_apps" msgid="6206161195076057075">"מתבצעת הפעלה של אפליקציות."</string>
<string name="android_upgrading_complete" msgid="409800058018374746">"תהליך האתחול בשלבי סיום."</string>
- <string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"לחצת על לחצן ההפעלה – בדרך כלל הפעולה הזו מכבה את המסך.\n\nעליך לנסות להקיש בעדינות במהלך ההגדרה של טביעת האצבע שלך."</string>
+ <string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"לחצת על כפתור ההפעלה – בדרך כלל הפעולה הזו מכבה את המסך.\n\nעליך לנסות ללחוץ בעדינות במהלך ההגדרה של טביעת האצבע שלך."</string>
<string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"לסיום ההגדרה, יש לכבות את המסך"</string>
<string name="fp_power_button_enrollment_button_text" msgid="3199783266386029200">"כיבוי"</string>
<string name="fp_power_button_bp_title" msgid="5585506104526820067">"להמשיך לאמת את טביעת האצבע שלך?"</string>
- <string name="fp_power_button_bp_message" msgid="2983163038168903393">"לחצת על לחצן ההפעלה – בדרך כלל הפעולה הזו מכבה את המסך.\n\nעליך לנסות להקיש בעדינות כדי לאמת את טביעת האצבע שלך."</string>
+ <string name="fp_power_button_bp_message" msgid="2983163038168903393">"לחצת על כפתור ההפעלה – בדרך כלל הפעולה הזו מכבה את המסך.\n\nעליך לנסות ללחוץ בעדינות כדי לאמת את טביעת האצבע שלך."</string>
<string name="fp_power_button_bp_positive_button" msgid="728945472408552251">"כיבוי המסך"</string>
<string name="fp_power_button_bp_negative_button" msgid="3971364246496775178">"המשך"</string>
<string name="heavy_weight_notification" msgid="8382784283600329576">"האפליקציה <xliff:g id="APP">%1$s</xliff:g> פועלת"</string>
- <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"יש להקיש כדי לחזור למשחק"</string>
+ <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"יש ללחוץ כדי לחזור למשחק"</string>
<string name="heavy_weight_switcher_title" msgid="3861984210040100886">"בחירת משחק"</string>
<string name="heavy_weight_switcher_text" msgid="6814316627367160126">"לקבלת ביצועים טובים יותר, רק אחד מבין המשחקים האלה יכול להיות פתוח בכל פעם."</string>
<string name="old_app_action" msgid="725331621042848590">"חזרה אל <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
@@ -1331,7 +1334,7 @@
<string name="new_app_description" msgid="1958903080400806644">"אפליקציית <xliff:g id="OLD_APP">%1$s</xliff:g> תיסגר ללא שמירה"</string>
<string name="dump_heap_notification" msgid="5316644945404825032">"<xliff:g id="PROC">%1$s</xliff:g> חורג ממגבלת הזיכרון"</string>
<string name="dump_heap_ready_notification" msgid="2302452262927390268">"תמונת מצב של הזיכרון מוכנה עבור <xliff:g id="PROC">%1$s</xliff:g>"</string>
- <string name="dump_heap_notification_detail" msgid="8431586843001054050">"‏Dump של ערימה נאסף. יש להקיש כדי לשתף."</string>
+ <string name="dump_heap_notification_detail" msgid="8431586843001054050">"‏Dump של ערימה נאסף. יש ללחוץ כדי לשתף."</string>
<string name="dump_heap_title" msgid="4367128917229233901">"לשתף את תמונת המצב של הזיכרון?"</string>
<string name="dump_heap_text" msgid="1692649033835719336">"התהליך <xliff:g id="PROC">%1$s</xliff:g> חרג ממגבלת הזיכרון בגודל <xliff:g id="SIZE">%2$s</xliff:g>‏. תמונת מצב של הזיכרון זמינה לשיתוף עם המפתח. חשוב לנקוט זהירות: תמונת המצב של הזיכרון עשויה לכלול מידע אישי שאליו יש לאפליקציה גישה."</string>
<string name="dump_heap_system_text" msgid="6805155514925350849">"‏התהליך <xliff:g id="PROC">%1$s</xliff:g> חרג ממגבלת הזיכרון בגודל <xliff:g id="SIZE">%2$s</xliff:g>. יש Dump של ערימה זמין לשיתוף. חשוב לנקוט זהירות: ה-Dump של הערימה עשוי לכלול מידע אישי רגיש שאליו יש לתהליך גישה. ייתכן שמידע זה כולל נתונים שהקלדת."</string>
@@ -1363,12 +1366,12 @@
<!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
<skip />
<string name="wifi_no_internet" msgid="1386911698276448061">"ל-<xliff:g id="NETWORK_SSID">%1$s</xliff:g> אין גישה לאינטרנט"</string>
- <string name="wifi_no_internet_detailed" msgid="634938444133558942">"יש להקיש לצפייה באפשרויות"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"יש ללחוץ לצפייה באפשרויות"</string>
<string name="mobile_no_internet" msgid="4014455157529909781">"לרשת הסלולרית אין גישה לאינטרנט"</string>
<string name="other_networks_no_internet" msgid="6698711684200067033">"לרשת אין גישה לאינטרנט"</string>
<string name="private_dns_broken_detailed" msgid="3709388271074611847">"‏לא ניתן לגשת לשרת DNS הפרטי"</string>
<string name="network_partial_connectivity" msgid="4791024923851432291">"הקישוריות של <xliff:g id="NETWORK_SSID">%1$s</xliff:g> מוגבלת"</string>
- <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"יש להקיש כדי להתחבר בכל זאת"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"יש ללחוץ כדי להתחבר בכל זאת"</string>
<string name="network_switch_metered" msgid="1531869544142283384">"מעבר אל <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="1358296010128405906">"המכשיר משתמש ברשת <xliff:g id="NEW_NETWORK">%1$s</xliff:g> כשלרשת <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> אין גישה לאינטרנט. עשויים לחול חיובים."</string>
<string name="network_switch_metered_toast" msgid="501662047275723743">"בוצע מעבר מרשת <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> לרשת <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1407,7 +1410,11 @@
<string name="install_carrier_app_notification_text_app_name" msgid="4086877327264106484">"‏אפשר להוריד את האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> כדי להפעיל את כרטיס ה-SIM החדש"</string>
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"להורדת האפליקציה"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"‏ה-SIM החדש הוכנס"</string>
- <string name="carrier_app_notification_text" msgid="6567057546341958637">"יש להקיש כדי להגדיר"</string>
+ <string name="carrier_app_notification_text" msgid="6567057546341958637">"יש ללחוץ כדי להגדיר"</string>
+ <!-- no translation found for time_zone_change_notification_title (5232503069219193218) -->
+ <skip />
+ <!-- no translation found for time_zone_change_notification_body (6135793674904665585) -->
+ <skip />
<string name="time_picker_dialog_title" msgid="9053376764985220821">"הגדרת שעה"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"הגדרת תאריך"</string>
<string name="date_time_set" msgid="4603445265164486816">"הגדרה"</string>
@@ -1425,15 +1432,15 @@
<string name="usb_midi_notification_title" msgid="7404506788950595557">"‏MIDI באמצעות USB מופעל"</string>
<string name="usb_uvc_notification_title" msgid="2030032862673400008">"המכשיר מחובר כמצלמת אינטרנט"</string>
<string name="usb_accessory_notification_title" msgid="1385394660861956980">"‏אביזר USB מחובר"</string>
- <string name="usb_notification_message" msgid="4715163067192110676">"אפשר להקיש כאן כדי לראות אפשרויות נוספות"</string>
- <string name="usb_power_notification_message" msgid="7284765627437897702">"המכשיר המחובר בטעינה. יש להקיש לאפשרויות נוספות."</string>
+ <string name="usb_notification_message" msgid="4715163067192110676">"אפשר ללחוץ כאן כדי לראות אפשרויות נוספות"</string>
+ <string name="usb_power_notification_message" msgid="7284765627437897702">"המכשיר המחובר בטעינה. יש ללחוץ לאפשרויות נוספות."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"המכשיר זיהה התקן אודיו אנלוגי"</string>
- <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"ההתקן שחיברת לא תואם לטלפון הזה. יש להקיש לקבלת מידע נוסף."</string>
+ <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"ההתקן שחיברת לא תואם לטלפון הזה. יש ללחוץ לקבלת מידע נוסף."</string>
<string name="adb_active_notification_title" msgid="408390247354560331">"‏ניפוי באגים ב-USB מחובר"</string>
- <string name="adb_active_notification_message" msgid="5617264033476778211">"‏צריך להקיש כדי להשבית את ניפוי הבאגים ב-USB"</string>
+ <string name="adb_active_notification_message" msgid="5617264033476778211">"‏צריך ללחוץ כדי להשבית את ניפוי הבאגים ב-USB"</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"‏יש ללחוץ על ההתראה כדי להשבית ניפוי באגים ב-USB."</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ניפוי הבאגים האלחוטי מחובר"</string>
- <string name="adbwifi_active_notification_message" msgid="930987922852867972">"יש להקיש כדי להשבית ניפוי באגים אלחוטי"</string>
+ <string name="adbwifi_active_notification_message" msgid="930987922852867972">"יש ללחוץ כדי להשבית ניפוי באגים אלחוטי"</string>
<string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"יש לבחור כדי להשבית ניפוי באגים אלחוטי."</string>
<string name="test_harness_mode_notification_title" msgid="2282785860014142511">"מצב מסגרת בדיקה הופעל"</string>
<string name="test_harness_mode_notification_message" msgid="3039123743127958420">"כדי להשבית את מצב \'מסגרת בדיקה\' צריך לאפס להגדרות היצרן."</string>
@@ -1444,7 +1451,7 @@
<string name="mte_override_notification_title" msgid="4731115381962792944">"‏ה-MTE הניסיוני הופעל"</string>
<string name="mte_override_notification_message" msgid="2441170442725738942">"‏יכולה להיות השפעה על הביצועים והיציבות. יש להפעיל מחדש כדי להשבית. אם ההפעלה מתבצעת באמצעות arm64.memtag.bootctl, צריך להגדיר מראש לערך none."</string>
<string name="usb_contaminant_detected_title" msgid="4359048603069159678">"‏יש נוזלים או חלקיקים ביציאת ה-USB"</string>
- <string name="usb_contaminant_detected_message" msgid="7346100585390795743">"‏יציאת ה-USB הושבתה באופן אוטומטי. יש להקיש לקבלת מידע נוסף."</string>
+ <string name="usb_contaminant_detected_message" msgid="7346100585390795743">"‏יציאת ה-USB הושבתה באופן אוטומטי. יש ללחוץ לקבלת מידע נוסף."</string>
<string name="usb_contaminant_not_detected_title" msgid="2651167729563264053">"‏ניתן להשתמש ביציאת ה-USB"</string>
<string name="usb_contaminant_not_detected_message" msgid="892863190942660462">"הטלפון לא מזהה יותר נוזלים וחלקיקים."</string>
<string name="taking_remote_bugreport_notification_title" msgid="1582531382166919850">"עיבוד דוח על באג..."</string>
@@ -1459,32 +1466,32 @@
<string name="hardware" msgid="3611039921284836033">"שימוש במקלדת שמופיעה במסך"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"הגדרה של <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"הגדרת מקלדות פיזיות"</string>
- <string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"יש להקיש כדי לבחור שפה ופריסה"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"יש ללחוץ כדי לבחור שפה ופריסה"</string>
<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">"הצגה מעל אפליקציות אחרות"</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_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>
<string name="ext_media_checking_notification_message" product="tv" msgid="7986154434946021415">"אחסון המדיה בתהליך ניתוח"</string>
<string name="ext_media_new_notification_title" msgid="3517407571407687677">"<xliff:g id="NAME">%s</xliff:g> חדש"</string>
<string name="ext_media_new_notification_title" product="automotive" msgid="9085349544984742727">"המדיה <xliff:g id="NAME">%s</xliff:g> לא פועלת"</string>
- <string name="ext_media_new_notification_message" msgid="6095403121990786986">"צריך להקיש כדי להגדיר"</string>
+ <string name="ext_media_new_notification_message" msgid="6095403121990786986">"צריך ללחוץ כדי להגדיר"</string>
<string name="ext_media_new_notification_message" product="tv" msgid="216863352100263668">"יש לבחור כדי להגדיר"</string>
- <string name="ext_media_new_notification_message" product="automotive" msgid="5140127881613227162">"ייתכן שיהיה צורך לפרמט מחדש את המכשיר. יש להקיש כדי להוציא את המדיה."</string>
+ <string name="ext_media_new_notification_message" product="automotive" msgid="5140127881613227162">"ייתכן שיהיה צורך לפרמט מחדש את המכשיר. יש ללחוץ כדי להוציא את המדיה."</string>
<string name="ext_media_ready_notification_message" msgid="7509496364380197369">"לאחסון של תמונות, סרטונים, מוזיקה ועוד"</string>
<string name="ext_media_ready_notification_message" product="tv" msgid="8847134811163165935">"עיון בקובצי המדיה"</string>
<string name="ext_media_unmountable_notification_title" msgid="4895444667278979910">"בעיה עם <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_unmountable_notification_title" product="automotive" msgid="3142723758949023280">"המדיה <xliff:g id="NAME">%s</xliff:g> לא פועלת"</string>
- <string name="ext_media_unmountable_notification_message" msgid="3256290114063126205">"יש להקיש כדי לפתור את הבעיה"</string>
+ <string name="ext_media_unmountable_notification_message" msgid="3256290114063126205">"יש ללחוץ כדי לפתור את הבעיה"</string>
<string name="ext_media_unmountable_notification_message" product="tv" msgid="3003611129979934633">"<xliff:g id="NAME">%s</xliff:g> פגום. יש ללחוץ כדי לפתור את הבעיה."</string>
- <string name="ext_media_unmountable_notification_message" product="automotive" msgid="2274596120715020680">"ייתכן שיהיה צורך לפרמט מחדש את המכשיר. יש להקיש כדי להוציא את המדיה."</string>
+ <string name="ext_media_unmountable_notification_message" product="automotive" msgid="2274596120715020680">"ייתכן שיהיה צורך לפרמט מחדש את המכשיר. יש ללחוץ כדי להוציא את המדיה."</string>
<string name="ext_media_unsupported_notification_title" msgid="3487534182861251401">"בוצע זיהוי של <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_unsupported_notification_title" product="automotive" msgid="6004193172658722381">"המדיה <xliff:g id="NAME">%s</xliff:g> לא פועלת"</string>
- <string name="ext_media_unsupported_notification_message" msgid="8463636521459807981">"יש להקיש כדי להגדיר"</string>
+ <string name="ext_media_unsupported_notification_message" msgid="8463636521459807981">"יש ללחוץ כדי להגדיר"</string>
<string name="ext_media_unsupported_notification_message" product="tv" msgid="1595482802187036532">"יש לבחור כדי להגדיר את <xliff:g id="NAME">%s</xliff:g> בפורמט נתמך."</string>
<string name="ext_media_unsupported_notification_message" product="automotive" msgid="3412494732736336330">"ייתכן שיהיה צורך לפרמט מחדש את המכשיר"</string>
<string name="ext_media_badremoval_notification_title" msgid="4114625551266196872">"<xliff:g id="NAME">%s</xliff:g> הוסר באופן בלתי צפוי"</string>
@@ -1529,7 +1536,7 @@
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"מאפשרת לאפליקציה לבקש רשות להתעלם מאופטימיזציות של הסוללה לאפליקציה הזו."</string>
<string name="permlab_queryAllPackages" msgid="2928450604653281650">"שליחת שאילתות לכל החבילות"</string>
<string name="permdesc_queryAllPackages" msgid="5339069855520996010">"מאפשרת לאפליקציה לראות את כל החבילות המותקנות."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"יש להקיש פעמיים לשינוי המרחק מהתצוגה"</string>
+ <string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"יש ללחוץ פעמיים לשינוי המרחק מהתצוגה"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"‏לא ניתן להוסיף widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"התחלה"</string>
<string name="ime_action_search" msgid="4501435960587287668">"חיפוש"</string>
@@ -1561,8 +1568,8 @@
<string name="notification_ranker_binding_label" msgid="432708245635563763">"שירות של דירוג התראות"</string>
<string name="vpn_title" msgid="5906991595291514182">"‏VPN מופעל"</string>
<string name="vpn_title_long" msgid="6834144390504619998">"‏VPN מופעל על ידי <xliff:g id="APP">%s</xliff:g>"</string>
- <string name="vpn_text" msgid="2275388920267251078">"יש להקיש כדי לנהל את הרשת."</string>
- <string name="vpn_text_long" msgid="278540576806169831">"בוצע חיבור אל <xliff:g id="SESSION">%s</xliff:g>. יש להקיש כדי לנהל את הרשת."</string>
+ <string name="vpn_text" msgid="2275388920267251078">"יש ללחוץ כדי לנהל את הרשת."</string>
+ <string name="vpn_text_long" msgid="278540576806169831">"בוצע חיבור אל <xliff:g id="SESSION">%s</xliff:g>. יש ללחוץ כדי לנהל את הרשת."</string>
<string name="vpn_lockdown_connecting" msgid="6096725311950342607">"‏ה-VPN שמופעל תמיד, מתחבר..."</string>
<string name="vpn_lockdown_connected" msgid="2853127976590658469">"‏ה-VPN שפועל תמיד, מחובר"</string>
<string name="vpn_lockdown_disconnected" msgid="5573611651300764955">"‏אין חיבור ל-VPN שפועל כל הזמן"</string>
@@ -1573,7 +1580,7 @@
<string name="reset" msgid="3865826612628171429">"איפוס"</string>
<string name="submit" msgid="862795280643405865">"שליחה"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"אפליקציית הנהיגה פועלת"</string>
- <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"יש להקיש כדי לצאת מאפליקציית הנהיגה."</string>
+ <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"יש ללחוץ כדי לצאת מאפליקציית הנהיגה."</string>
<string name="back_button_label" msgid="4078224038025043387">"הקודם"</string>
<string name="next_button_label" msgid="6040209156399907780">"הבא"</string>
<string name="skip_button_label" msgid="3566599811326688389">"דילוג"</string>
@@ -1652,7 +1659,7 @@
<string name="data_usage_wifi_limit_snoozed_title" msgid="1622359254521960508">"‏חריגה ממגבלת נתוני ה-Wi-Fi"</string>
<string name="data_usage_limit_snoozed_body" msgid="545146591766765678">"חרגת ב-<xliff:g id="SIZE">%s</xliff:g> מעבר למגבלה המוגדרת"</string>
<string name="data_usage_restricted_title" msgid="126711424380051268">"נתוני הרקע מוגבלים"</string>
- <string name="data_usage_restricted_body" msgid="5338694433686077733">"יש להקיש כדי להסיר את ההגבלה."</string>
+ <string name="data_usage_restricted_body" msgid="5338694433686077733">"יש ללחוץ כדי להסיר את ההגבלה."</string>
<string name="data_usage_rapid_title" msgid="2950192123248740375">"שימוש מוגבר בחבילת הגלישה"</string>
<string name="data_usage_rapid_body" msgid="3886676853263693432">"האפליקציות שלך השתמשו בנתונים רבים יותר מהרגיל"</string>
<string name="data_usage_rapid_app_body" msgid="5425779218506513861">"האפליקציה <xliff:g id="APP">%s</xliff:g> השתמשה בנתונים רבים יותר מהרגיל"</string>
@@ -1748,7 +1755,7 @@
<string name="csd_dose_reached_warning" product="default" msgid="491875107583931974">"להמשיך להאזין בעוצמת קול גבוהה?\n\nעוצמת הקול של האוזניות הייתה גבוהה במשך יותר זמן מהמומלץ, מה שעלול להזיק לשמיעה"</string>
<string name="csd_momentary_exposure_warning" product="default" msgid="7730840903435405501">"זוהה צליל חזק\n\nעוצמת הקול של האוזניות הייתה גבוהה מהמומלץ, מה שעלול להזיק לשמיעה"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"להשתמש בקיצור הדרך לתכונת הנגישות?"</string>
- <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"כשקיצור הדרך מופעל, לחיצה על שני לחצני עוצמת הקול למשך שלוש שניות מפעילה את תכונת הנגישות."</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"כשקיצור הדרך מופעל, לחיצה על שני כפתורי עוצמת הקול למשך שלוש שניות מפעילה את תכונת הנגישות."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"האם להפעיל את מקש הקיצור לתכונות הנגישות?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"לחיצה ארוכה על שני לחצני עוצמת הקול למשך מספר שניות מפעילה את תכונות הנגישות. בעקבות זאת, ייתכן שאופן הפעולה של המכשיר ישתנה.\n\nהתכונות הנוכחיות:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nניתן לשנות את התכונות שנבחרו ב\'הגדרות\' &gt; \'נגישות\'."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
@@ -1768,8 +1775,8 @@
<string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"עדיף שלא"</string>
<string name="accessibility_dialog_button_uninstall" msgid="2952465517671708108">"הסרה"</string>
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"אפליקציה מסתירה את בקשת ההרשאה כך שלא ניתן לאמת את התשובה שלך."</string>
- <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"יש להקיש על תכונה כדי להתחיל להשתמש בה:"</string>
- <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"בחירת תכונה לשימוש עם לחצן הנגישות"</string>
+ <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"יש ללחוץ על תכונה כדי להתחיל להשתמש בה:"</string>
+ <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"בחירת תכונה לשימוש עם כפתור הנגישות"</string>
<string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"בחירת תכונות לשימוש עם קיצור דרך באמצעות מקשי עוצמת הקול"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"שירות <xliff:g id="SERVICE_NAME">%s</xliff:g> כבוי"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"עריכת קיצורי הדרך"</string>
@@ -1781,24 +1788,32 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"מצב שימוש ביד אחת"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"מעומעם במיוחד"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"מכשירי שמיעה"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"מנותק"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"מחובר"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"פעיל"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"בטעינה"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"לחצני עוצמת הקול נלחצו בלחיצה ארוכה. שירות <xliff:g id="SERVICE_NAME">%1$s</xliff:g> הופעל."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"לחצני עוצמת הקול נלחצו בלחיצה ארוכה. שירות <xliff:g id="SERVICE_NAME">%1$s</xliff:g> הושבת."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"אפשר לשחרר את מקש עוצמת הקול. כדי להפעיל את השירות <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, צריך ללחוץ לחיצה ארוכה על שני המקשים של עוצמת הקול שוב במשך 3 שניות."</string>
<string name="accessibility_button_prompt_text" msgid="6105393217162198616">"בחירת תכונה"</string>
<string name="accessibility_gesture_prompt_text" msgid="6452246951969541792">"בחירת תכונה"</string>
<string name="accessibility_gesture_3finger_prompt_text" msgid="77745752309056152">"בחירת תכונה"</string>
- <string name="accessibility_button_instructional_text" msgid="6831154884557881996">"התכונה תיפתח בפעם הבאה שתזוהה הקשה על לחצן הנגישות"</string>
+ <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>
+ <!-- no translation found for hearing_device_switch_phone_mic_notification_title (6645178038359708836) -->
+ <skip />
+ <!-- no translation found for hearing_device_switch_hearing_mic_notification_title (4612074852145289569) -->
+ <skip />
+ <!-- no translation found for hearing_device_switch_phone_mic_notification_text (1332426273666077412) -->
+ <skip />
+ <!-- no translation found for hearing_device_switch_hearing_mic_notification_text (8288368365767284208) -->
+ <skip />
+ <!-- no translation found for hearing_device_notification_switch_button (3619524619430941300) -->
+ <skip />
+ <!-- no translation found for hearing_device_notification_settings_button (6673651052880279178) -->
+ <skip />
<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>
<string name="user_logging_out_message" msgid="7216437629179710359">"מתבצע ניתוק של <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1908,7 +1923,7 @@
<string name="reason_unknown" msgid="5599739807581133337">"לא ידוע"</string>
<string name="reason_service_unavailable" msgid="5288405248063804713">"שירות ההדפסה לא הופעל"</string>
<string name="print_service_installed_title" msgid="6134880817336942482">"שירות <xliff:g id="NAME">%s</xliff:g> מותקן"</string>
- <string name="print_service_installed_message" msgid="7005672469916968131">"יש להקיש כדי להפעיל את השירות"</string>
+ <string name="print_service_installed_message" msgid="7005672469916968131">"יש ללחוץ כדי להפעיל את השירות"</string>
<string name="restr_pin_enter_admin_pin" msgid="1199419462726962697">"יש להזין את קוד האימות של מנהל המכשיר"</string>
<string name="restr_pin_enter_pin" msgid="373139384161304555">"יש להזין קוד אימות"</string>
<string name="restr_pin_incorrect" msgid="3861383632940852496">"שגוי"</string>
@@ -1946,7 +1961,7 @@
<string name="confirm_battery_saver" msgid="5247976246208245754">"אישור"</string>
<string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"התכונה \'חיסכון בסוללה\' מפעילה עיצוב כהה ומגבילה או מכבה פעילות ברקע, חלק מהאפקטים החזותיים, תכונות מסוימות וחלק מהחיבורים לרשתות."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"התכונה \'חיסכון בסוללה\' מפעילה עיצוב כהה ומגבילה או מכבה פעילות ברקע, חלק מהאפקטים החזותיים, תכונות מסוימות וחלק מהחיבורים לרשתות."</string>
- <string name="data_saver_description" msgid="4995164271550590517">"‏כדי לסייע בהפחתת השימוש בנתונים, חוסך הנתונים (Data Saver) מונע מאפליקציות מסוימות לשלוח או לקבל נתונים ברקע. אפליקציות שבהן נעשה שימוש כרגע יכולות לגשת לנתונים, אבל בתדירות נמוכה יותר. המשמעות היא, למשל, שתמונות יוצגו רק לאחר שמקישים עליהן."</string>
+ <string name="data_saver_description" msgid="4995164271550590517">"‏כדי לסייע בהפחתת השימוש בנתונים, חוסך הנתונים (Data Saver) מונע מאפליקציות מסוימות לשלוח או לקבל נתונים ברקע. אפליקציות שבהן נעשה שימוש כרגע יכולות לגשת לנתונים, אבל בתדירות נמוכה יותר. המשמעות היא, למשל, שתמונות יוצגו רק לאחר שלוחצים עליהן."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"להפעיל את חוסך הנתונים?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"הפעלה"</string>
<string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{למשך דקה אחת (עד {formattedTime})}one{למשך # דקות (עד{formattedTime})}two{למשך # דקות (עד{formattedTime})}other{למשך # דקות (עד{formattedTime})}}"</string>
@@ -2076,9 +2091,9 @@
<string name="new_sms_notification_content" msgid="3197949934153460639">"‏יש לפתוח את אפליקציית ה-SMS כדי להציג"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"ייתכן שחלק מהפונקציונליות תהיה מוגבלת"</string>
<string name="profile_encrypted_detail" msgid="5279730442756849055">"פרופיל העבודה נעול"</string>
- <string name="profile_encrypted_message" msgid="1128512616293157802">"יש להקיש לביטול נעילת פרופיל העבודה"</string>
+ <string name="profile_encrypted_message" msgid="1128512616293157802">"יש ללחוץ לביטול נעילת פרופיל העבודה"</string>
<string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"התבצע חיבור אל <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
- <string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"יש להקיש כדי להציג קבצים"</string>
+ <string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"יש ללחוץ כדי להציג קבצים"</string>
<string name="pin_target" msgid="8036028973110156895">"הצמדה"</string>
<string name="pin_specific_target" msgid="7824671240625957415">"הצמדה של‏ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="unpin_target" msgid="3963318576590204447">"ביטול הצמדה"</string>
@@ -2165,7 +2180,7 @@
<string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"שיחות והתראות יושתקו"</string>
<string name="notification_channel_system_changes" msgid="2462010596920209678">"שינויים במערכת"</string>
<string name="review_notification_settings_title" msgid="5102557424459810820">"בדיקת הגדרת ההתראות"</string>
- <string name="review_notification_settings_text" msgid="5916244866751849279">"‏החל מגרסת Android 13, אפליקציות שיותקנו יוכלו לשלוח התראות רק אם יקבלו ממך הרשאה. אפשר להקיש כדי לשנות את ההרשאה הזו באפליקציות קיימות."</string>
+ <string name="review_notification_settings_text" msgid="5916244866751849279">"‏החל מגרסת Android 13, אפליקציות שיותקנו יוכלו לשלוח התראות רק אם יקבלו ממך הרשאה. אפשר ללחוץ כדי לשנות את ההרשאה הזו באפליקציות קיימות."</string>
<string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"תזכירו לי מאוחר יותר"</string>
<string name="review_notification_settings_dismiss" msgid="4160916504616428294">"סגירה"</string>
<string name="notification_app_name_system" msgid="3045196791746735601">"מערכת"</string>
@@ -2174,10 +2189,10 @@
<string name="notification_appops_microphone_active" msgid="581333393214739332">"מיקרופון"</string>
<string name="notification_appops_overlay_active" msgid="5571732753262836481">"תצוגה מעל אפליקציות אחרות במסך"</string>
<string name="notification_feedback_indicator" msgid="663476517711323016">"שליחת משוב"</string>
- <string name="notification_feedback_indicator_alerted" msgid="6552871804121942099">"ההתראה הזו שודרגה ל\'ברירת מחדל\'. יש להקיש כדי לשלוח משוב."</string>
- <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ההתראה הזו הורדה בדרגה ל\'שקטה\'. יש להקיש כדי לשלוח משוב."</string>
- <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"דירוג ההתראה הזו הוגבה. יש להקיש כדי לשלוח משוב."</string>
- <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ההתראה הזו דורגה נמוך יותר. יש להקיש כדי לשלוח משוב."</string>
+ <string name="notification_feedback_indicator_alerted" msgid="6552871804121942099">"ההתראה הזו שודרגה ל\'ברירת מחדל\'. יש ללחוץ כדי לשלוח משוב."</string>
+ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ההתראה הזו הורדה בדרגה ל\'שקטה\'. יש ללחוץ כדי לשלוח משוב."</string>
+ <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"דירוג ההתראה הזו הוגבה. יש ללחוץ כדי לשלוח משוב."</string>
+ <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ההתראה הזו דורגה נמוך יותר. יש ללחוץ כדי לשלוח משוב."</string>
<string name="nas_upgrade_notification_title" msgid="8436359459300146555">"התראות משופרות"</string>
<string name="nas_upgrade_notification_content" msgid="5157550369837103337">"‏ההתראות המשופרות מספקות מעכשיו הצעות לפעולות ולתשובות. אין יותר תמיכה בהתראות מותאמות ל-Android."</string>
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"אישור"</string>
@@ -2394,14 +2409,14 @@
<string name="splash_screen_view_icon_description" msgid="180638751260598187">"סמל האפליקציה"</string>
<string name="splash_screen_view_branding_description" msgid="7911129347402728216">"תדמית המותג של האפליקציה"</string>
<string name="view_and_control_notification_title" msgid="4300765399209912240">"בדיקה של הגדרות הגישה"</string>
- <string name="view_and_control_notification_content" msgid="8003766498562604034">"לשירות <xliff:g id="SERVICE_NAME">%s</xliff:g> יש הרשאה להצגת המסך ושליטה בו. אפשר להקיש כדי לבדוק."</string>
+ <string name="view_and_control_notification_content" msgid="8003766498562604034">"לשירות <xliff:g id="SERVICE_NAME">%s</xliff:g> יש הרשאה להצגת המסך ושליטה בו. אפשר ללחוץ כדי לבדוק."</string>
<string name="ui_translation_accessibility_translated_text" msgid="3197547218178944544">"ההודעה <xliff:g id="MESSAGE">%1$s</xliff:g> תורגמה."</string>
<string name="ui_translation_accessibility_translation_finished" msgid="3057830947610088465">"ההודעה תורגמה מ<xliff:g id="FROM_LANGUAGE">%1$s</xliff:g> ל<xliff:g id="TO_LANGUAGE">%2$s</xliff:g>."</string>
<string name="notification_channel_abusive_bg_apps" msgid="6092140213264920355">"פעילות ברקע"</string>
<string name="notification_title_abusive_bg_apps" msgid="994230770856147656">"אחת האפליקציות מרוקנת את הסוללה"</string>
<string name="notification_title_long_running_fgs" msgid="8170284286477131587">"אפליקציה כלשהי עדיין פעילה"</string>
- <string name="notification_content_abusive_bg_apps" msgid="5296898075922695259">"<xliff:g id="APP">%1$s</xliff:g> פועלת ברקע. יש להקיש כדי לנהל את השימוש בסוללה."</string>
- <string name="notification_content_long_running_fgs" msgid="8258193410039977101">"האפליקציה <xliff:g id="APP">%1$s</xliff:g> עלולה להשפיע על חיי הסוללה. אפשר להקיש כדי לבדוק את האפליקציות הפעילות."</string>
+ <string name="notification_content_abusive_bg_apps" msgid="5296898075922695259">"<xliff:g id="APP">%1$s</xliff:g> פועלת ברקע. יש ללחוץ כדי לנהל את השימוש בסוללה."</string>
+ <string name="notification_content_long_running_fgs" msgid="8258193410039977101">"האפליקציה <xliff:g id="APP">%1$s</xliff:g> עלולה להשפיע על חיי הסוללה. אפשר ללחוץ כדי לבדוק את האפליקציות הפעילות."</string>
<string name="notification_action_check_bg_apps" msgid="4758877443365362532">"כדאי לבדוק את האפליקציות הפעילות"</string>
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"לא ניתן לגשת למצלמה של הטלפון מה‑<xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"לא ניתן לגשת למצלמה של הטאבלט מה‑<xliff:g id="DEVICE">%1$s</xliff:g>"</string>
@@ -2432,12 +2447,12 @@
<string name="device_state_notification_settings_button" msgid="691937505741872749">"מעבר להגדרות"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"השבתה"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"המקלדת <xliff:g id="DEVICE_NAME">%s</xliff:g> הוגדרה"</string>
- <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"פריסת המקלדת מוגדרת ל<xliff:g id="LAYOUT_1">%s</xliff:g>. אפשר להקיש כדי לשנות את ההגדרה הזו."</string>
- <string name="keyboard_layout_notification_two_selected_message" msgid="1876349944065922950">"פריסת המקלדת מוגדרת ל<xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>. אפשר להקיש כדי לשנות את ההגדרה הזו."</string>
- <string name="keyboard_layout_notification_three_selected_message" msgid="280734264593115419">"פריסת המקלדת מוגדרת ל<xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>. אפשר להקיש כדי לשנות את ההגדרה הזו."</string>
- <string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"פריסת המקלדת מוגדרת ל<xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… אפשר להקיש כדי לשנות את ההגדרה הזו."</string>
+ <string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"פריסת המקלדת מוגדרת ל<xliff:g id="LAYOUT_1">%s</xliff:g>. אפשר ללחוץ כדי לשנות את ההגדרה הזו."</string>
+ <string name="keyboard_layout_notification_two_selected_message" msgid="1876349944065922950">"פריסת המקלדת מוגדרת ל<xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>. אפשר ללחוץ כדי לשנות את ההגדרה הזו."</string>
+ <string name="keyboard_layout_notification_three_selected_message" msgid="280734264593115419">"פריסת המקלדת מוגדרת ל<xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>. אפשר ללחוץ כדי לשנות את ההגדרה הזו."</string>
+ <string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"פריסת המקלדת מוגדרת ל<xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… אפשר ללחוץ כדי לשנות את ההגדרה הזו."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"הוגדרו מקלדות פיזיות"</string>
- <string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"יש להקיש כדי להציג את המקלדות"</string>
+ <string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"יש ללחוץ כדי להציג את המקלדות"</string>
<string name="profile_label_private" msgid="6463418670715290696">"פרטי"</string>
<string name="profile_label_clone" msgid="769106052210954285">"שכפול"</string>
<string name="profile_label_work" msgid="3495359133038584618">"פרופיל עבודה"</string>
@@ -2455,6 +2470,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"רוצה לשלוח הודעות באמצעות תקשורת לוויינית?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"‏אפשר לשלוח ולקבל הודעות ללא רשת סלולרית או Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"‏לפתיחת Messages"</string>
@@ -2500,7 +2517,7 @@
<string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"שעון מעורר של <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="bg_user_sound_notification_button_switch_user" msgid="3091969648572788946">"החלפת משתמש"</string>
<string name="bg_user_sound_notification_button_mute" msgid="4942158515665615243">"השתקה"</string>
- <string name="bg_user_sound_notification_message" msgid="8613881975316976673">"כדי להשתיק את הצליל, צריך להקיש כאן"</string>
+ <string name="bg_user_sound_notification_message" msgid="8613881975316976673">"כדי להשתיק את הצליל, צריך ללחוץ כאן"</string>
<string name="keyboard_shortcut_group_applications_browser" msgid="6535007304687100909">"דפדפן"</string>
<string name="keyboard_shortcut_group_applications_contacts" msgid="2750702518068326356">"אנשי קשר"</string>
<string name="keyboard_shortcut_group_applications_email" msgid="4229037666415353683">"אימייל"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 05adb2b13e4d..51dca2255a83 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"モバイル ネットワークにアクセスできません"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"タップして、優先ネットワークを変更してください。"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"緊急通報は利用できません"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"今後表示しない"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"緊急通報にはモバイル ネットワークが必要です"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"通知"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"電話の転送"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"ネットワーク通知"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"ネットワークを利用できます"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN のステータス"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"時刻とタイムゾーン"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"IT 管理者からの通知"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"通知"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"販売店デモ"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"実行中のアプリ"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"電池を消費しているアプリ"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"拡大"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"補聴器"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"ユーザー補助の使用"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"ディスプレイ"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」がバッテリーを使用しています"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"アプリをダウンロード"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"新しい SIM が挿入されました"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"タップして設定"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"タイムゾーンを変更しました"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"<xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g>(<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)に変更しました"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"時刻設定"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"日付設定"</string>
<string name="date_time_set" msgid="4603445265164486816">"設定"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"片手モード"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"さらに輝度を下げる"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"補聴器"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"未接続"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"接続済み"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"有効"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"読み込んでいます"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"音量ボタンを長押ししました。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> が ON になりました。"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"音量ボタンを長押ししました。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> が OFF になりました。"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"音量ボタンを離してください。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> を有効にするには音量大と音量小の両方のボタンを 3 秒ほど長押ししてください。"</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"スマートフォンのマイクに切り替えますか?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"補聴器のマイクに切り替えますか?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"音質を向上させるために、または補聴器のバッテリー残量が少ない場合に使用します。通話時のみマイクが切り替わります。"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"補聴器のマイクを使ってハンズフリー通話を行えます。通話時のみマイクが切り替わります。"</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"切り替える"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"設定"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> をログアウトしています…"</string>
@@ -2454,6 +2459,7 @@
<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_summary_with_data" msgid="6486843676720429049">"衛星経由でのメッセージの送受信とデータの使用(上限あり)が可能です"</string>
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"衛星通信メッセージを使用しますか?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"モバイル ネットワークや Wi-Fi ネットワークがなくてもメッセージを送受信できます"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"メッセージ アプリを開く"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 552f52e0c128..2411c8cad961 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"მობილურ ქსელთან დაკავშირება ვერ ხერხდება"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ცადეთ უპირატესი ქსელის შეცვლა. შეეხეთ შესაცვლელად."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"გადაუდებელი ზარი მიუწვდომელია"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"აღარ გამოჩნდეს"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"გადაუდებელი ზარები საჭიროებს მობილურ ქსელს"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"გაფრთხილებები"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ზარის გადამისამართება"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"ქსელის გაფრთხილებები"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"ქსელი ხელმისაწვდომია"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN-ის სტატუსი"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"დრო და სასაათო სარტყელი"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"გაფრთხილებები თქვენი IT ადმინისტრატორისგან"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"გაფრთხილებები"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"დემო-რეჟიმი საცალო მოვაჭრეებისთვის"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"აპი გაშვებულია"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"ბატარეის მხარჯავი აპები"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"გადიდება"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"სმენის აპარატი"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"მარტივი წვდომის გამოყენება"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"ეკრანი"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> იყენებს ბატარეას"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"აპის ჩამოტვირთვა"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"მოთავსებულია ახალი SIM ბარათი"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"შეეხეთ პარამეტრების დასაყენებლად"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"თქვენი სასაათო სარტყელი შეიცვალა"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"თქვენ ახლა იმყოფებით შემდეგ სასაათო სარტყელში: <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"დროის დაყენება"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"თარიღის დაყენება"</string>
<string name="date_time_set" msgid="4603445265164486816">"დაყენება"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ცალი ხელის რეჟიმი"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"დამატებითი დაბინდვა"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"სმენის აპარატები"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"კავშირი გაწყვეტილია"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"დაკავშირებული"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"აქტიური"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"იტვირთება"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ხანგრძლივად დააჭირეთ ხმის ღილაკებს. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ჩართულია."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ხანგრძლივად დააჭირეთ ხმის ღილაკებს. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> გამორთულია."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"ხელი აუშვით ხმის ღილაკებს. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-ის ჩასართველად, ხელმეორედ ხანგრძლივად დააჭირეთ ორივე ხმის ღილაკს 3 წამის განმავლობაში."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"გსურთ ტელეფონის მიკროფონზე გადართვა?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"გსურთ სმენის მოწყობილობის მიკროფონზე გადართვა?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"უკეთესი ხმისთვის ან, თუ თქვენი სმენის მოწყობილობის ბატარეა სუსტადაა დამუხტული. ეს გადართავს თქვენს მიკროფონს მხოლოდ ზარის დროს."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"შეგიძლიათ სმენის მოწყობილობის მიკროფონის გამოყენება უკონტაქტოდ დასარეკად. ეს გადართავს თქვენს მიკროფონს მხოლოდ ზარის დროს."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"გადართვა"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"პარამეტრები"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g>-ის ანგარიშიდან გასვლა…"</string>
@@ -2454,6 +2459,7 @@
<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_summary_with_data" msgid="6486843676720429049">"შეგიძლიათ გაგზავნოთ და მიიღოთ შეტყობინებები და გამოიყენოთ შეზღუდული მონაცემები სატელიტით"</string>
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"გსურთ შეტყობინებების სატელიტური მიმოცვლის გამოყენება?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"შეტყობინებების გაგზავნა და მიღება მობილური ან Wi-Fi ქსელის გარეშე"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages-ის გახსნა"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 3c118ac715b5..e1fd8d1a8d82 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Мобильдік желіге қосылу мүмкін емес"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Таңдаулы желіні өзгертіп көріңіз. Өзгерту үшін түртіңіз."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Жедел қызметке қоңырау шалу мүмкін емес"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Қайта көрсетілмесін"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Құтқару қызметіне қоңырау шалу үшін мобильдік желі қажет."</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Дабылдар"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Қоңырауды басқа нөмірге бағыттау"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Желі дабылдары"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Желі қолжетімді"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN күйі"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Уақыт және уақыт белдеулері"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"АТ әкімшісі жіберген ескертулер"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Дабылдар"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Бөлшек саудаға арналған демо нұсқасы"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Қолданба қосулы"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Батареяны пайдаланып жатқан қолданбалар"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Ұлғайту"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Есту құрылғысы"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Арнайы мүмкіндіктерді қолдану"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Дисплей"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> батареяны пайдалануда"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Қолданбаны жүктеп алу"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Жаңа SIM салынды"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Оны орнату үшін түртіңіз"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Уақыт белдеуі өзгертілді"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Қазір <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) уақыт белдеуіндесіз."</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Уақытты реттеу"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Мезгілін реттеу"</string>
<string name="date_time_set" msgid="4603445265164486816">"Орнату"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Бір қолмен басқару режимі"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Экранды қарайту"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Есту аппараттары"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Ажыратылды"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Қосылды"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Белсенді"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Жүктеліп жатыр"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Пайдаланушы дыбыс деңгейі пернелерін басып ұстап тұрды. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қосулы."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Дыбыс деңгейі пернелерін басып тұрған соң, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> өшірілді."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Дыбыс деңгейі пернелерін жіберіңіз. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін қосу үшін дыбыс деңгейі пернесінің екеуін де қайтадан 3 секундқа басып тұрыңыз."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Телефонның микрофонына ауысу керек пе?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Есту аппаратының микрофонына ауысу керек пе?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Дауыс жақсы шығу үшін немесе есту аппаратының батарея заряды аз болған жағдайда пайдалануға болады. Микрофонға тек қоңырау кезінде ауысады."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Дауыспен басқару арқылы қоңырау шалу үшін есту аппаратының микрофонын пайдалана аласыз. Микрофонға тек қоңырау кезінде ауысады."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Ауысу"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Параметрлер"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> ішінен шығу…"</string>
@@ -2454,6 +2459,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Жерсерік арқылы хабар алмасасыз ба?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Хабарландыруларды мобильдік желіге немесе Wi-Fi желісіне қосылмай жіберіңіз және алыңыз."</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages қолданбасын ашу"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 737fe883930c..190693976be1 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"មិន​អាច​ភ្ជាប់​បណ្ដាញ​ទូរសព្ទ​ចល័តបានទេ"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"សាកល្បង​ប្ដូរ​ទៅបណ្ដាញ​ដែល​ចង់ប្រើ។ សូមចុច​ដើម្បីផ្លាស់​ប្ដូរ។"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"មិន​អាច​ប្រើ​ការ​ហៅ​បន្ទាន់​បានទេ"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"កុំ​បង្ហាញ​ទៀត"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"ការហៅទៅលេខសង្គ្រោះបន្ទាន់តម្រូវឱ្យមានបណ្ដាញ​ទូរសព្ទ​ចល័ត"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"ការជូនដំណឹង"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ការបញ្ជូន​ការហៅ​ទូរសព្ទ​បន្ត"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"ការ​ជូនដំណឹង​អំពី​បណ្តាញ"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"មានបណ្តាញ"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"ស្ថានភាព VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"ម៉ោង និងល្វែងម៉ោង"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"ការជូនដំណឹង​ពី​អ្នកគ្រប់គ្រង​ផ្នែកព័ត៌មានវិទ្យា​របស់អ្នក"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"ការ​ជូនដំណឹង"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"របៀបដាក់បង្ហាញក្នុងហាង"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"កម្មវិធី​ដែល​កំពុង​ដំណើរការ"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"កម្មវិធីដែល​កំពុងប្រើថ្ម"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"ការពង្រីក"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"ឧបករណ៍ជំនួយការស្ដាប់"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"ការប្រើប្រាស់​ភាពងាយស្រួល"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"ផ្ទាំងអេក្រង់"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងប្រើថ្ម"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"ទាញយក​កម្មវិធី"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"ស៊ីមកាតថ្មីត្រូវបានស៊កចូល"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"ប៉ះដើម្បីដំឡើង"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"ល្វែងម៉ោងរបស់អ្នកបានផ្លាស់ប្ដូរ"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"ឥឡូវនេះ អ្នកស្ថិតនៅ <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"កំណត់​ម៉ោង​"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"កំណត់​កាល​បរិច្ឆេទ​"</string>
<string name="date_time_set" msgid="4603445265164486816">"កំណត់"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"មុខងារប្រើដៃម្ខាង"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ងងឹតខ្លាំង"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"ឧបករណ៍ជំនួយការស្ដាប់"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"បាន​ផ្ដាច់"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"បានភ្ជាប់"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"សកម្ម"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"កំពុងផ្ទុក"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"បានសង្កត់​គ្រាប់ចុច​កម្រិតសំឡេង​ជាប់។ បាន​បើក <xliff:g id="SERVICE_NAME">%1$s</xliff:g>។"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"បានសង្កត់​គ្រាប់ចុច​កម្រិតសំឡេង​ជាប់។ បាន​បិទ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>។"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"លែង​គ្រាប់ចុចកម្រិតសំឡេង។ ដើម្បីបើក <xliff:g id="SERVICE_NAME">%1$s</xliff:g> សូមចុច​គ្រាប់ចុចកម្រិតសំឡេងទាំងពីរឱ្យជាប់ម្ដងទៀត​រយៈពេល 3 វិនាទី។"</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"ប្ដូរទៅមីក្រូហ្វូនទូរសព្ទឬ?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"ប្ដូរទៅមីក្រូហ្វូនឧបករណ៍​ជំនួយការ​ស្ដាប់ឬ?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"ដើម្បីទទួលបានសំឡេងកាន់តែប្រសើរ ឬប្រសិនបើថ្មឧបករណ៍​ជំនួយការ​ស្ដាប់របស់អ្នកជិតអស់។ ការធ្វើបែបនេះប្ដូរមីក្រូហ្វូនរបស់អ្នក ក្នុងអំឡុងការហៅទូរសព្ទតែប៉ុណ្ណោះ។"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"អ្នកអាចប្រើមីក្រូហ្វូនឧបករណ៍​ជំនួយការ​ស្ដាប់របស់អ្នកសម្រាប់ការហៅទូរសព្ទដោយមិន​ប្រើ​ដៃ។ ការធ្វើបែបនេះប្ដូរមីក្រូហ្វូនរបស់អ្នក ក្នុងអំឡុងការហៅទូរសព្ទតែប៉ុណ្ណោះ។"</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"ប្ដូរ"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ការកំណត់"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"កំពុងចេញ <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2454,6 +2459,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"ប្រើ​ការ​ផ្ញើ​សារ​តាម​ផ្កាយរណប​ឬ?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"ផ្ញើ និងទទួលសារដោយគ្មានបណ្ដាញ Wi-Fi ឬបណ្ដាញទូរសព្ទចល័ត"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"បើក​កម្មវិធី Messages"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 87a0bef2ceb6..9c11160f502d 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ಮೊಬೈಲ್‌ ನೆಟ್‌ವರ್ಕ್ ತಲುಪಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ಆದ್ಯತೆಗೊಳಿಸಿದ ನೆಟ್‌ವರ್ಕ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಪ್ರಯತ್ನಿಸಿ. ಬದಲಾಯಿಸಲು ಟ್ಯಾಪ್‌ ಮಾಡಿ."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ತುರ್ತು ಕರೆ ಮಾಡುವಿಕೆ ಲಭ್ಯವಿಲ್ಲ"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"ಪುನಃ ತೋರಿಸಬೇಡಿ"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"ತುರ್ತು ಕರೆಗಳಿಗೆ ಮೊಬೈಲ್ ನೆಟ್‌ವರ್ಕ್‌ನ ಅಗತ್ಯವಿದೆ"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"ಎಚ್ಚರಿಕೆಗಳು"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ಕರೆ ಫಾರ್ವರ್ಡ್‌ ಮಾಡುವಿಕೆ"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"ನೆಟ್‌ವರ್ಕ್ ಎಚ್ಚರಿಕೆಗಳು"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"ನೆಟ್‌ವರ್ಕ್ ಲಭ್ಯವಿದೆ"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN ಸ್ಥಿತಿ"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"ಸಮಯ ಹಾಗೂ ಸಮಯ ವಲಯಗಳು"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"ನಿಮ್ಮ IT ವಿಭಾಗದ ನಿರ್ವಾಹಕರಿಂದ ಎಚ್ಚರಿಕೆಗಳು"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"ಎಚ್ಚರಿಕೆಗಳು"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"ರಿಟೇಲ್ ಡೆಮೋ"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"App ರನ್ ಆಗುತ್ತಿದೆ"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಬ್ಯಾಟರಿಯನ್ನು ಉಪಯೋಗಿಸುತ್ತಿವೆ"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"ಹಿಗ್ಗಿಸುವಿಕೆ"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"ಹಿಯರಿಂಗ್ ಸಾಧನ"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"ಪ್ರವೇಶಿಸುವಿಕೆಯ ಬಳಕೆ"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"ಡಿಸ್‌ಪ್ಲೇ"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಆ್ಯಪ್, ಬ್ಯಾಟರಿಯನ್ನು ಬಳಸುತ್ತಿದೆ"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"ಆ್ಯಪ್‌ ಡೌನ್‌ಲೋಡ್ ಮಾಡಿ"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"ಹೊಸ ಸಿಮ್ ಸೇರಿಸಲಾಗಿದೆ"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"ಇದನ್ನು ಸ್ಥಾಪಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"ನಿಮ್ಮ ಸಮಯವಲಯ ಬದಲಾಗಿದೆ."</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"ನೀವು ಈಗ <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) ನಲ್ಲಿದ್ದೀರಿ"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"ಸಮಯವನ್ನು ಸೆಟ್ ಮಾಡಿ"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"ದಿನಾಂಕವನ್ನು ಸೆಟ್ ಮಾಡಿ"</string>
<string name="date_time_set" msgid="4603445265164486816">"ಹೊಂದಿಸು"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ಒಂದು ಕೈ ಮೋಡ್‌"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ಇನ್ನಷ್ಟು ಮಬ್ಬು"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"ಶ್ರವಣ ಸಾಧನಗಳು"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ಡಿಸ್‌ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"ಸಕ್ರಿಯವಾಗಿದೆ"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"ಲೋಡ್ ಆಗುತ್ತಿದೆ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಹಿಡಿದುಕೊಳ್ಳಿ. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳಲಾಗಿದೆ. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಬಿಡುಗಡೆ ಮಾಡಿ. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಆನ್ ಮಾಡಲು, ಎರಡೂ ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಮತ್ತೊಮ್ಮೆ 3 ಸೆಕೆಂಡ್‌ಗಳ ಕಾಲ ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"ಫೋನ್ ಮೈಕ್‌ಗೆ ಬದಲಿಸಬೇಕೆ?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"ಶ್ರವಣ ಸಾಧನ ಮೈಕ್‌ಗೆ ಬದಲಿಸಬೇಕೆ?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"ಉತ್ತಮ ಧ್ವನಿಗಾಗಿ ಅಥವಾ ನಿಮ್ಮ ಶ್ರವಣ ಸಾಧನದ ಬ್ಯಾಟರಿ ಕಡಿಮೆಯಿದ್ದರೆ. ಇದು ಕರೆಯ ಸಮಯದಲ್ಲಿ ಮಾತ್ರ ನಿಮ್ಮ ಮೈಕ್ ಅನ್ನು ಬದಲಾಯಿಸುತ್ತದೆ."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"ಹ್ಯಾಂಡ್ಸ್-ಫ್ರೀ ಕರೆ ಮಾಡುವಿಕೆಗಾಗಿ ನಿಮ್ಮ ಶ್ರವಣ ಸಾಧನದ ಮೈಕ್ರೊಫೋನ್ ಅನ್ನು ನೀವು ಬಳಸಬಹುದು. ಇದು ಕರೆಯ ಸಮಯದಲ್ಲಿ ಮಾತ್ರ ನಿಮ್ಮ ಮೈಕ್ ಅನ್ನು ಬದಲಾಯಿಸುತ್ತದೆ."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"ಬದಲಿಸಿ"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರನ್ನು ಲಾಗ್‌ ಔಟ್‌ ಮಾಡಲಾಗುತ್ತಿದೆ…"</string>
@@ -2454,6 +2459,8 @@
<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">"ನೀವು ಮೊಬೈಲ್ ಅಥವಾ ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್ ಇಲ್ಲದೆಯೇ ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಬಹುದು ಮತ್ತು ಸ್ವೀಕರಿಸಬಹುದು"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"ಸ್ಯಾಟಲೈಟ್ ಮೆಸೇಜಿಂಗ್ ಅನ್ನು ಬಳಸಬೇಕೆ?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"ಮೊಬೈಲ್ ಅಥವಾ ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್ ಇಲ್ಲದೆಯೇ ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಿ ಮತ್ತು ಸ್ವೀಕರಿಸಿ"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ಅನ್ನು ತೆರೆಯಿರಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 51921be8b6b4..1b302e633fa7 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"모바일 네트워크에 연결할 수 없습니다."</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"기본 네트워크를 변경해 보세요. 탭하여 변경할 수 있습니다."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"긴급 전화를 사용할 수 없습니다."</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"다시 표시 안 함"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"긴급 전화를 걸려면 모바일 네트워크 연결이 필요함"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"알림"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"착신전환"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"네트워크 알림"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"네트워크 사용 가능"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN 상태"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"시간 및 시간대"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"IT 관리자가 보낸 알림"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"알림"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"소매 데모"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"실행 중인 앱"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"배터리를 소모하는 앱"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"확대"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"청각 보조 기기"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"접근성 사용"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"디스플레이"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 배터리 사용 중"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"앱 다운로드"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"새 SIM이 삽입됨"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"탭하여 설정"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"시간대가 변경되었습니다"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"현재 시간대는 <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g>(<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)입니다."</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"시간 설정"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"날짜 설정"</string>
<string name="date_time_set" msgid="4603445265164486816">"설정"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"한 손 모드"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"더 어둡게"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"청각 보조 기기"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"연결 끊김"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"연결됨"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"활성"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"로드 중"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"볼륨 키를 길게 눌렀습니다. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 설정되었습니다."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"볼륨 키를 길게 눌렀습니다. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 중지되었습니다."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"볼륨 키에서 손을 뗍니다. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>을 켜려면 볼륨 키 2개를 3초 동안 길게 누르세요."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"휴대전화 마이크로 전환하시겠습니까?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"보청기 마이크로 전환하시겠습니까?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"더 나은 음질을 원하거나 보청기 배터리가 부족한 경우 전환할 수 있습니다. 통화 중에만 마이크가 전환됩니다."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"보청기 마이크로 핸즈프리 통화 기능을 이용할 수 있습니다. 통화 중에만 마이크가 전환됩니다."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"전환"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"설정"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g>님을 로그아웃하는 중…"</string>
@@ -2454,6 +2459,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"위성 메시지를 사용하시겠습니까?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"모바일 또는 Wi-Fi 네트워크 없이 메시지 주고받기"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"메시지 열기"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 7ca2092dddf0..58a6d8486caf 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Мобилдик тармакка туташпай жатат"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Тандалган тармакты өзгөртүп көрүңүз. Өзгөртүү үчүн таптаңыз."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Шашылыш чалуу жеткиликсиз"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Экинчи көрүнбөсүн"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Шашылыш чалуу үчүн мобилдик тармак талап кылынат"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Шашылыш билдирүүлөр"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Чалууну башка номерге багыттоо"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Тармактын эскертүүлөрү"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Жеткиликтүү тармактар"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN абалы"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Убакыт жана убакыт алкактары"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"IT администраторуңуздан келген билдирүүлөр"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Шашылыш билдирүүлөр"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Чекене соода дүкөнү үчүн демо режим"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Колдонмо иштеп жатат"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Колдонмолор батареяңызды коротууда"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Чоңойтуу"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Угуу аппараты"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Атайын мүмкүнчүлүктөрдүн колдонулушу"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Экран"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу батареяны пайдаланып жатат"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Колдонмону жүктөп алуу"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Жаңы SIM карта салынды"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Аны жөндөө үчүн таптап коюңуз"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Убакыт алкагыңыз өзгөрдү"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Учурдагы убакыт алкагы: <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Убакытты коюу"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Күндү коюу"</string>
<string name="date_time_set" msgid="4603445265164486816">"Коюу"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Бир кол режими"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Кошумча караңгылатуу"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Угуу түзмөктөрү"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Ажыратылды"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Туташты"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Жигердүү"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Жүктөлүүдө"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Үндү катуулатуу/акырындатуу баскычтары басылып, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> күйгүзүлдү."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Үндү катуулатуу/акырындатуу баскычтары басылып, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> өчүрүлдү."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Үн баскычтарын коё бериңиз. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын күйгүзүү үчүн үн баскычтарын кайра 3 секунд коё бербей басып туруңуз."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Телефондун микрофонуна которуласызбы?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Угуу аппаратынын микрофонуна которуласызбы?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Үндүн сапатын жакшыртуу үчүн же угуу аппаратыңыздын батареясы аз болсо, телефондун микрофонун колдоно аласыз. Микрофонуңуз чалуу учурунда гана которулат."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Угуу аппаратыңыздын микрофонун үн режиминде чалуу үчүн колдоно аласыз. Микрофонуңуз чалуу учурунда гана которулат."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Которулуу"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Параметрлер"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> чыгууда…"</string>
@@ -2454,6 +2459,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Спутник аркылуу байланышасызбы?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Мобилдик же Wi-Fi тармагына туташпай эле билдирүүлөрдү жөнөтүп, алыңыз"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Жазышуулар колдонмосун ачуу"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 32b0605b1128..3c3c58ba281a 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ບໍ່ສາມາດຕິດຕໍ່ເຄືອຂ່າຍມືຖືໄດ້"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ໃຫ້ລອງປ່ຽນເຄືອຂ່າຍທີ່ຕ້ອງການ. ແຕະເພື່ອປ່ຽນ."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ບໍ່ສາມາດໃຊ້ການໂທສຸກເສີນໄດ້"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"ບໍ່ຕ້ອງສະແດງອີກ"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"ໂທ​ສຸກ​ເສີນຕ້ອງໃຊ້ເຄືອຂ່າຍມືຖື"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"ການເຕືອນ"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ການໂອນສາຍ"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"ແຈ້ງເຕືອນເຄືອຂ່າຍ"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"ມີເຄືອຂ່າຍທີ່ສາມາດໃຊ້ໄດ້"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"ສະຖານະ VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"ເວລາ ແລະ ເຂດເວລາ"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"ການເຕືອນຈາກຜູ້ເບິ່ງແຍງໄອທີຂອງທ່ານ"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"ການເຕືອນ"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"ເດໂມສຳລັບຮ້ານຂາຍ"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"ແອັບກຳລັງເຮັດວຽກ"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"ແອັບທີ່ກຳລັງໃຊ້ແບັດເຕີຣີ"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"ການຂະຫຍາຍ"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"ອຸປະກອນຊ່ວຍຟັງ"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"ການໃຊ້ການຊ່ວຍເຂົ້າເຖິງ"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"ຈໍສະແດງຜົນ"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກຳລັງໃຊ້ແບັດເຕີຣີຢູ່"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"ດາວໂຫລດແອັບ"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"ໃສ່ SIM ໃໝ່ແລ້ວ"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"ແຕະເພື່ອຕັ້ງມັນ"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"ເຂດເວລາຂອງທ່ານມີການປ່ຽນແປງ"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"ຕອນນີ້ທ່ານຢູ່ໃນເຂດເວລາ <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"ຕັ້ງເວລາ"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"ກໍານົດວັນທີ"</string>
<string name="date_time_set" msgid="4603445265164486816">"ຕັ້ງຄ່າ"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ໂໝດມືດຽວ"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ຫຼຸດແສງເປັນພິເສດ"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"ອຸປະກອນຊ່ວຍຟັງ"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ຕັດການເຊື່ອມຕໍ່ແລ້ວ"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"ເຊື່ອມຕໍ່ແລ້ວ"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"ນຳໃຊ້ຢູ່"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"ກຳລັງໂຫຼດ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ກົດປຸ່ມລະດັບສຽງຄ້າງໄວ້. ເປີດໃຊ້ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ແລ້ວ."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ກົດປຸ່ມລະດັບສຽງຄ້າງໄວ້. ປິດ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ໄວ້ແລ້ວ."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"ປ່ອຍປຸ່ມລະດັບສຽງ. ເພື່ອເປີດ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, ໃຫ້ກົດປຸ່ມລະດັບສຽງທັງສອງຄ້າງໄວ້ 3 ວິນາທີ."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"ປ່ຽນໄປໃຊ້ໄມໂຄຣໂຟນຂອງໂທລະສັບບໍ?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"ປ່ຽນໄປໃຊ້ໄມໂຄຣໂຟນຂອງເຄື່ອງຊ່ວຍຟັງບໍ?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"ເພື່ອໃຫ້ສຽງດີຂຶ້ນ ຫຼື ໃນກໍລະນີທີ່ແບັດເຕີຣີຂອງເຄື່ອງຊ່ວຍຟັງຂອງທ່ານໃກ້ໝົດ. ການດຳເນີນການນີ້ພຽງແຕ່ປ່ຽນໄມໂຄຣໂຟນຂອງທ່ານໃນລະຫວ່າງການໂທເທົ່ານັ້ນ."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"ທ່ານສາມາດໃຊ້ໄມໂຄຣໂຟນຂອງເຄື່ອງຊ່ວຍຟັງເພື່ອການໂທແບບແຮນຟຣີໄດ້. ການດຳເນີນການນີ້ພຽງແຕ່ປ່ຽນໄມໂຄຣໂຟນຂອງທ່ານໃນລະຫວ່າງການໂທເທົ່ານັ້ນ."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"ປ່ຽນ"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ການຕັ້ງຄ່າ"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"ກຳລັງອອກຈາກລະບົບ <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2454,6 +2459,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"ໃຊ້ການຮັບສົ່ງຂໍ້ຄວາມຜ່ານດາວທຽມບໍ?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"ຮັບ ແລະ ສົ່ງຂໍ້ຄວາມໂດຍບໍ່ຕ້ອງໃຊ້ເຄືອຂ່າຍໂທລະສັບມືຖື ຫຼື Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"ເປີດ Messages"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index ff7919e4e55a..3c56808d883e 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -89,8 +89,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Nepavyko pasiekti mobiliojo ryšio tinklo"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Pabandykite pakeisti pageidaujamą tinklą. Palieskite, kad pakeistumėte."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Skambučių pagalbos numeriu paslauga nepasiekiama"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Daugiau nerodyti"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Kad būtų galima skambinti pagalbos numeriais, būtina naudoti mobiliojo ryšio tinklą"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Įspėjimai"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Skambučio peradresavimas"</string>
@@ -305,6 +304,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Tinklo įspėjimai"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Tinklas pasiekiamas"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN būsena"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Laikas ir laiko juostos"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"IT administratoriaus įspėjimai"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Įspėjimai"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demonstracinė versija mažmenininkams"</string>
@@ -312,6 +312,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Programa paleista"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Programos, naudojančios akumuliatoriaus energiją"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Didinimas"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Klausos įrenginys"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Pritaikomumo funkcijų naudojimas"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Ekranas"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ naudoja akumuliatoriaus energiją"</string>
@@ -1409,6 +1410,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Atsisiųsti programą"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Įdėta nauja SIM kortelė"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Jei norite tai nustatyti, palieskite"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Jūsų laiko juosta pakeista"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Dabar esate <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Nustatyti laiką"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Nustatyti datą"</string>
<string name="date_time_set" msgid="4603445265164486816">"Nustatyti"</string>
@@ -1782,14 +1785,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Vienos rankos režimas"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Itin blanku"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Klausos įrenginiai"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Atjungta"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Prisijungta"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktyvus"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Įkeliama"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Laikomi garsumo klavišai. „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“ įjungta."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Laikomi garsumo klavišai. „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“ išjungta."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Atleiskite garsumo klavišus. Kad įjungtumėte „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“, paspauskite ir 3 sekundes palaikykite garsumo klavišus."</string>
@@ -1800,6 +1799,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Perjungti į telefono mikrofoną?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Perjungti į klausos aparato mikrofoną?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Kad būtų geresnis garsas arba jei klausos aparato akumuliatorius beveik išsikrovęs. Mikrofonas įjungiamas tik per skambutį."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Galite naudoti klausos aparato mikrofoną skambučiams laisvų rankų režimu. Mikrofonas įjungiamas tik per skambutį."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Perjungti"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Nustatymai"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Atsijungiama (<xliff:g id="NAME">%1$s</xliff:g>)…"</string>
@@ -2456,6 +2461,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Programos turinys paslėptas bendrinant ekraną saugumo sumetimais"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Automatiškai prisijungta prie palydovinio ryšio"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Galite siųsti ir gauti pranešimus be mobiliojo ryšio ar „Wi-Fi“ tinklo"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Naudoti susirašinėjimą palydoviniais pranešimais?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Siųskite ir gaukite pranešimus be mobiliojo ryšio ar „Wi-Fi“ tinklo"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Atidaryti programą „Messages“"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index ab2c242cb55c..1870883fcc5e 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -88,8 +88,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Nevar sasniegt mobilo tīklu"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Mēģiniet nomainīt vēlamo tīklu. Pieskarieties, lai to mainītu."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Nav pieejami ārkārtas izsaukumi"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Vairs nerādīt"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Lai veiktu ārkārtas zvanus, ir nepieciešams mobilais tīkls."</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Brīdinājumi"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Zvanu pāradresācija"</string>
@@ -304,6 +303,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Tīkla brīdinājumi"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Tīkls ir pieejams"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN statuss"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Laiks un laika joslas"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Brīdinājumi no jūsu IT administratora"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Brīdinājumi"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demonstrācijas versija veikaliem"</string>
@@ -311,6 +311,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Lietotne darbojas"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Lietotnes, kas patērē akumulatora jaudu"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Palielinājums"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Dzirdes aparāts"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Pieejamības lietojums"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Displejs"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> izmanto akumulatoru"</string>
@@ -1408,6 +1409,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Lejupielādēt lietotni"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Ievietota jauna SIM karte"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Pieskarieties, lai to iestatītu."</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Jūsu laika josla ir mainīta"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Jūs tagad atrodaties šajā laika joslā: <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Iestatīt laiku"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Datuma iestatīšana"</string>
<string name="date_time_set" msgid="4603445265164486816">"Iestatīt"</string>
@@ -1781,14 +1784,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Vienas rokas režīms"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Papildu aptumšošana"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Dzirdes aparāti"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Atvienota"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Pievienota"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktīva"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Notiek ielāde"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Turējāt nospiestas skaļuma pogas. Pakalpojums <xliff:g id="SERVICE_NAME">%1$s</xliff:g> tika ieslēgts."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Turējāt nospiestas skaļuma pogas. Pakalpojums <xliff:g id="SERVICE_NAME">%1$s</xliff:g> tika izslēgts."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Atlaidiet skaļuma pogas. Lai ieslēgtu pakalpojumu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, vēlreiz nospiediet un trīs sekundes turiet nospiestas abas skaļuma pogas."</string>
@@ -1799,6 +1798,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Vai pārslēgt uz tālruņa mikrofonu?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Vai pārslēgt uz dzirdes aparāta mikrofonu?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Varat pārslēgt, lai iegūtu labāku skaņu vai ja dzirdes aparāta akumulatora uzlādes līmenis ir zems. Mikrofons tiek pārslēgts tikai zvana laikā."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Varat izmantot dzirdes aparāta mikrofonu zvaniem brīvroku režīmā. Mikrofons tiek pārslēgts tikai zvana laikā."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Pārslēgt"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Iestatījumi"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Notiek lietotāja <xliff:g id="NAME">%1$s</xliff:g> atteikšanās…"</string>
@@ -2455,6 +2460,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Drošības nolūkos lietotnes saturs kopīgotajā ekrānā ir paslēpts"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Automātiski izveidots savienojums ar satelītu"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Varat sūtīt un saņemt ziņojumus bez mobilā vai Wi-Fi tīkla."</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Vai izmantot satelīta ziņojumapmaiņu?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Sūtiet un saņemiet ziņojumus bez mobilā vai Wi‑Fi tīkla."</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Atvērt lietotni Ziņojumi"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index c10b1ef78361..1c9e022ca3aa 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Мобилната мрежа е недостапна"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Сменете ја претпочитаната мрежа. Допрете за промена."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Итните повици се недостапни"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Не прикажувај повторно"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"За итните повици е потребна мобилна мрежа"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Предупредувања"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Проследување повик"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Известувања на мрежа"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Има достапна мрежа"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN-статус"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Време и временски зони"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Предупредувања од администраторот за интернет"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Предупредувања"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Демонстрација за малопродажба"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Апликацијата работи"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Апликации што ја трошат батеријата"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Зголемување"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Слушен апарат"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Користење на пристапноста"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Екран"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> користи батерија"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Преземете апликација"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Вметната е нова SIM-картичка"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Допрете за да поставите"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Вашата временска зона се промени"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Во моментов сте во <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Постави време"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Постави датум"</string>
<string name="date_time_set" msgid="4603445265164486816">"Постави"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Режим со една рака"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Дополнително затемнување"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слушни помагала"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Не е поврзано"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Поврзано"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Активно"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Се вчитува"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ги задржавте копчињата за јачина на звук. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е вклучена."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ги задржавте копчињата за јачина на звук. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е исклучена."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Ослободете ги копчињата за јачина на звукот. Притиснете ги и задржете ги двете копчиња за јачина на звукот во траење од 3 секунди за да вклучите <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Да се префрли на микрофонот на телефонот?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Да се префрли на микрофонот на слушното помагало?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"За подобар звук или ако е слаба батеријата на вашето слушно помагало. Ова го префрла вашиот микрофон само за време на повикот."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Може да го користите вашиот микрофон на слушното помагало за повикување без користење раце. Ова го префрла вашиот микрофон само за време на повикот."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Префрли"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Поставки"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> се одјавува…"</string>
@@ -2454,6 +2459,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Да се користи „Сателитска размена на пораки“?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Испраќајте и примајте пораки без мобилна или Wi-Fi мрежа"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Отворете ја Messages"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 3eef4930796f..85dd3362990c 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"മൊബൈൽ നെറ്റ്‌വർക്കിലേക്ക് കണക്റ്റ് ചെയ്യാനാവുന്നില്ല"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"തിര‌ഞ്ഞെടുത്ത നെറ്റ്‌വർക്ക് മാറ്റുന്നത് പരീക്ഷിക്കുക. മാറ്റാൻ ടാപ്പ് ചെയ്യുക."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"എമർജൻസി കോളിംഗ് ലഭ്യമല്ല"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"വീണ്ടും കാണിക്കരുത്"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"എമർജൻസി കോളുകൾ ചെയ്യാൻ ഒരു മൊബൈൽ നെറ്റ്‌വർക്ക് ആവശ്യമാണ്"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"അലേർട്ടുകൾ"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"കോൾ ഫോർവേഡിംഗ്"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"നെറ്റ്‌വർക്ക് അലേർട്ടുകൾ"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"നെറ്റ്‌വർക്ക് ‌ലഭ്യമല്ല"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN നില"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"സമയവും സമയമേഖലകളും"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"നിങ്ങളുടെ ഐടി അഡ്‌മിനിൽ നിന്നുള്ള മുന്നറിയിപ്പുകൾ"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"അലേർട്ടുകൾ"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"റീട്ടെയിൽ ഡെമോ"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"ആപ്പ് പ്രവർത്തിക്കുന്നു"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"ആപ്പുകൾ ബാറ്ററി ഉപയോഗിക്കുന്നു"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"മാഗ്നിഫിക്കേഷൻ"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"കേൾവിക്കുള്ള ഉപകരണം"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"ഉപയോഗസഹായി ഉപയോഗം"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"ഡിസ്‌പ്ലേ"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> ബാറ്ററി ഉപയോഗിക്കുന്നു"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"ആപ്പ് ഡൗൺലോഡ് ചെയ്യുക"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"പുതിയ സിം ഇട്ടു"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"ഇത് സജ്ജമാക്കുന്നതിന് ടാപ്പുചെയ്യുക"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"നിങ്ങളുടെ സമയമേഖല മാറി"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"നിങ്ങൾ ഇപ്പോൾ <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) എന്നതിൽ ആണ്"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"സമയം സജ്ജീകരിക്കുക"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"ദിവസം സജ്ജീകരിക്കുക"</string>
<string name="date_time_set" msgid="4603445265164486816">"സജ്ജമാക്കുക"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ഒറ്റക്കൈ മോഡ്"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"കൂടുതൽ ഡിം ചെയ്യൽ"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"ശ്രവണ ഉപകരണങ്ങൾ"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"വിച്‌ഛേദിച്ചു"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"കണക്റ്റ് ചെയ്‌തു"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"സജീവം"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"ലോഡ് ചെയ്യുന്നു"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"വോളിയം കീകൾ പിടിച്ചു. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓണാക്കി."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"വോളിയം കീകൾ അമർത്തിപ്പിടിച്ചു. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓഫാക്കി."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"വോളിയം കീകൾ വിടുക. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓണാക്കാൻ, രണ്ട് വോളിയം കീകളും വീണ്ടും മൂന്ന് സെക്കൻഡ് അമർത്തിപ്പിടിക്കുക."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"ഫോൺ മൈക്കിലേക്ക് മാറണോ?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"ശ്രവണ സഹായി മൈക്കിലേക്ക് മാറണോ?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"മികച്ച ശബ്ദത്തിന് അല്ലെങ്കിൽ നിങ്ങളുടെ ശ്രവണ സഹായിയുടെ ബാറ്ററി കുറവാണെങ്കിൽ. ഇത് കോൾ സമയത്ത് മാത്രം നിങ്ങളുടെ മൈക്ക് മാറ്റുന്നു."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"ഹാൻഡ്‌സ്‌-ഫ്രീ ആയി കോൾ ചെയ്യാൻ നിങ്ങളുടെ ശ്രവണ സഹായി മൈക്രോഫോൺ ഉപയോഗിക്കാം. ഇത് കോൾ സമയത്ത് മാത്രം നിങ്ങളുടെ മൈക്ക് മാറ്റുന്നു."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"മാറുക"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ക്രമീകരണം"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> ലോഗൌട്ട് ചെയ്യുന്നു…"</string>
@@ -2454,6 +2459,7 @@
<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">"മൊബൈലോ വൈഫൈ നെറ്റ്‌വർക്കോ ഇല്ലാതെ തന്നെ സന്ദേശങ്ങൾ അയയ്‌ക്കാനും സ്വീകരിക്കാനും നിങ്ങൾക്ക് കഴിയും"</string>
+ <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"നിങ്ങൾക്ക് സാറ്റലൈറ്റ് വഴി സന്ദേശങ്ങൾ അയയ്‌ക്കാനും സ്വീകരിക്കാനും പരിമിതമായ ഡാറ്റ ഉപയോഗിക്കാനും കഴിയും"</string>
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"സാറ്റലൈറ്റ് സന്ദേശമയയ്ക്കൽ ഉപയോഗിക്കണോ?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"മൊബൈൽ അല്ലെങ്കിൽ വൈഫൈ നെറ്റ്‌വർക്ക് ഇല്ലാതെ സന്ദേശങ്ങൾ അയയ്ക്കുകയും സ്വീകരിക്കുകയും ചെയ്യുക"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages തുറക്കുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index f81cff89ca21..e70a95ce77d2 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Хөдөлгөөнт холбооны сүлжээнд холбогдох боломжгүй байна"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Сонгосон сүлжээг өөрчлөхөөр оролдоно уу. Өөрчлөхийн тулд товшино уу."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Яаралтай дуудлага хийх боломжгүй"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Дахиж бүү харуул"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Яаралтай дуудлагуудад хөдөлгөөнт холбооны сүлжээ шаардлагатай"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Сануулга"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Дуудлага шилжүүлэх"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Сүлжээний сануулга"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Сүлжээ боломжтой"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN төлөв"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Цаг, цагийн бүс"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Таны IT админаас илгээсэн сэрэмжлүүлэг"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Сануулга"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Жижиглэнгийн жишээ"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Апп ажиллаж байна"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Апп батарей ашиглаж байна"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Томруулах"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Сонсголын төхөөрөмж"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Хандалтын ашиглалт"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Дэлгэц"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> батарей ашиглаж байна"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Апп татаж авах"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Шинэ SIM-г оруулсан"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Үүнийг тохируулахын тулд дарна уу"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Таны цагийн бүс өөрчлөгдсөн"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Та одоо <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)-д байна"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Цагийн тохируулах"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Огноо оруулах"</string>
<string name="date_time_set" msgid="4603445265164486816">"Тохируулах"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Нэг гарын горим"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Хэт бүүдгэр"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Сонсголын төхөөрөмжүүд"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Салсан"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Холбогдсон"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Идэвхтэй"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Ачаалж байна"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Дууны түвшний түлхүүрийг удаан дарсан. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г асаалаа."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Дууны түвшний түлхүүрийг удаан дарсан. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г унтраалаа."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Дууны түвшний товчнуудыг суллана уу. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г асаахын тулд дууны түвшний 2 товчийг зэрэг 3 секундийн турш удаан дарна уу."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Утасны микрофон руу сэлгэх үү?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Сонсголын төхөөрөмжийн микрофон руу сэлгэх үү?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Дуу чимээг сайжруулахын тулд эсвэл таны сонсголын төхөөрөмжийн батарей бага бол. Энэ нь зөвхөн дуудлагын үеэр таны микрофоныг сэлгэнэ."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Та гараас хамаарахгүй дуудлагад сонсголын төхөөрөмжийнхөө микрофоныг ашиглаж болно. Энэ нь зөвхөн дуудлагын үеэр таны микрофоныг сэлгэнэ."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Сэлгэх"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Тохиргоо"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g>-с гарч байна…"</string>
@@ -2454,6 +2459,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Хиймэл дагуулаар дамжин мессеж бичихийг ашиглах уу?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Хөдөлгөөнт холбооны эсвэл Wi-Fi сүлжээгүйгээр мессеж илгээх болон хүлээн авах"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Мессежийг нээх"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 98fedef134b9..cbe6b979d1d8 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"मोबाइल नेटवर्क उपलब्ध नाही"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"प्राधान्य दिलेले नेटवर्क बदलण्याचा प्रयत्न करा. बदलण्यासाठी टॅप करा."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"आणीबाणी कॉलिंग अनुपलब्ध"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"पुन्हा दाखवू नका"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"आणीबाणी कॉलसाठी मोबाइल नेटवर्क आवश्यक आहे"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"अलर्ट"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"कॉल फॉरवर्डिंग"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"नेटवर्क सूचना"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"नेटवर्क उपलब्ध"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN स्थिती"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"वेळ आणि टाइम झोन"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"तुमच्या IT ॲडमिनकडून आलेल्या सूचना"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"सूचना"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"रीटेल डेमो"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"APP चालत आहे"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"बॅटरी लवकर संपवणारी अ‍ॅप्स"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"मॅग्निफिकेशन"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"श्रवणयंत्र"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"अ‍ॅक्सेसिबिलिटी वापर"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"डिस्प्ले"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> बॅटरी वापरत आहे"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"अ‍ॅप डाउनलोड करा"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"नवीन सिम घाला"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"ते सेट करण्यासाठी टॅप करा"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"तुमचा टाइम झोन बदलला आहे"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"आता तुम्ही <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) मध्ये आहात."</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"वेळ सेट करा"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"तारीख सेट करा"</string>
<string name="date_time_set" msgid="4603445265164486816">"सेट करा"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"एकहाती मोड"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"आणखी डिम"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"श्रवणयंत्रे"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"डिस्कनेक्ट केले आहे"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"कनेक्ट केले आहे"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"अ‍ॅक्टिव्ह"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"लोड करत आहे"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"धरून ठेवलेल्या व्हॉल्यूम की. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> सुरू केला आहे."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"धरून ठेवलेल्या व्हॉल्यूम की. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> बंद केले आहे."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"व्हॉल्यूम की रिलीझ करा. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> सुरू करण्यासाठी, दोन्ही व्हॉल्यूम की पुन्हा प्रेस करा आणि तीन सेकंदांसाठी धरून ठेवा."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"फोनच्या माइकवर स्विच करायचे आहे का?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"श्रवणयंत्राच्या माइकवर स्विच करायचे आहे का?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"चांगल्या आवाजासाठी किंवा तुमच्या श्रवणयंत्राची बॅटरी कमी असल्यास. यामुळे कॉलदरम्यान फक्त तुमचा माइक स्विच केला जातो."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"हँड्स-फ्री कॉलिंगसाठी तुम्ही तुमच्या श्रवणयंत्राचा मायक्रोफोन वापरू शकता. यामुळे कॉलदरम्यान फक्त तुमचा माइक स्विच केला जातो."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"स्विच करा"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"सेटिंग्ज"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> लॉग आउट करत आहे…"</string>
@@ -2454,6 +2459,8 @@
<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">"तुम्ही मोबाइल किंवा वाय-फाय नेटवर्कशिवाय मेसेज पाठवू आणि मिळवू शकता"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"सॅटेलाइट मेसेजिंग वापरायचे आहे का?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"मोबाइल किंवा वाय-फाय नेटवर्कशिवाय मेसेज पाठवणे आणि मिळवणे"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages उघडा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 2ce54d0ffc39..5cb9defbcd3e 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Tidak dapat mencapai rangkaian mudah alih"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Cuba tukar rangkaian pilihan. Ketik untuk menukar."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Panggilan kecemasan tidak tersedia"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Jangan Tunjukkan Lagi"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Rangkaian mudah alih diperlukan untuk membuat panggilan kecemasan"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Makluman"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Pemajuan panggilan"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Makluman rangkaian"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Rangkaian tersedia"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Status VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Masa dan zon waktu"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Makluman daripada pentadbir IT anda"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Makluman"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Tunjuk cara runcit"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Apl berjalan"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Apl yang menggunakan bateri"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Pembesaran"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Peranti pendengaran"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Penggunaan kebolehaksesan"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Paparan"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang menggunakan bateri"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Muat turun apl"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"SIM baharu dimasukkan"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Ketik untuk menyediakannya"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Zon waktu anda berubah"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Kini anda berada dalam <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Tetapkan masa"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Tetapkan tarikh"</string>
<string name="date_time_set" msgid="4603445265164486816">"Tetapkan"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mod sebelah tangan"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Amat malap"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Peranti pendengaran"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Diputuskan sambungan"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Disambungkan"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktif"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Memuatkan"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Kekunci kelantangan ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dihidupkan."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Kekunci kelantangan ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dimatikan."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Lepaskan kekunci kelantangan. Untuk menghidupkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, sila tekan dan tahan kedua-dua kekunci kelantangan sekali lagi selama 3 saat."</string>
@@ -1798,6 +1797,12 @@
<string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Ciri ini akan dibuka pada kali seterusnya anda menggunakan pintasan ini. Leret ke atas menggunakan 2 jari dari bahagian bawah skrin anda dan lepaskan dengan cepat."</string>
<string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Ciri ini akan dibuka pada kali seterusnya anda menggunakan pintasan ini. Leret ke atas menggunakan 3 jari dari bahagian bawah skrin anda dan lepaskan dengan cepat."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Pembesaran"</string>
+ <string name="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Tukar kepada mikrofon telefon?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Tukar kepada mikrofon alat bantu pendengaran?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Untuk mendapatkan bunyi yang lebih baik atau jika bateri alat bantu pendengaran anda lemah. Tindakan ini hanya menukar mikrofon anda semasa panggilan."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Anda boleh menggunakan mikrofon alat bantu pendengaran anda untuk membuat panggilan bebas tangan. Tindakan ini hanya menukar mikrofon anda semasa panggilan."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Tukar"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Tetapan"</string>
<string name="user_switched" msgid="7249833311585228097">"Pengguna semasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Beralih kepada <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="7216437629179710359">"Log keluar daripada <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2454,6 +2459,7 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Kandungan apl disembunyikan daripada perkongsian skrin untuk keselamatan"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Disambungkan secara automatik kepada satelit"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Anda boleh menghantar dan menerima mesej tanpa rangkaian mudah alih atau Wi-Fi"</string>
+ <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Anda boleh menghantar dan menerima mesej serta menggunakan data terhad melalui satelit"</string>
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Gunakan pemesejan satelit?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Hantar dan terima mesej tanpa rangkaian mudah alih atau Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Buka Messages"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 3e0187a225a0..432f7f9c6aa0 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"မိုဘိုင်းကွန်ရက် လိုင်းမရပါ"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ဦးစားပေးကွန်ရက်သို့ ပြောင်းကြည့်ပါ။ ပြောင်းရန် တို့ပါ။"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"အရေးပေါ်ခေါ်ဆိုမှု မရနိုင်ပါ"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"ထပ်မပြပါနှင့်"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"အရေးပေါ်ဖုန်းခေါ်ရန် မိုဘိုင်းကွန်ရက် လိုအပ်သည်"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"သတိပေးချက်များ"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"အဝင်ခေါ်ဆိုမှုအား ထပ်ဆင့်ပို့ခြင်း"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"ကွန်ရက် သတိပေးချက်များ"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"ကွန်ရက်ချိတ်ဆက်မှု ရရှိနိုင်ပါသည်"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN အခြေအနေ"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"အချိန်နှင့် ဒေသစံတော်ချိန်များ"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"သင်၏ IT စီမံခန့်ခွဲသူထံမှ သတိပေးချက်များ"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"သတိပေးချက်များ"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"လက်လီအရောင်းဆိုင် သရုပ်ပြမှု"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"APP လုပ်ဆောင်နေသည်"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"အက်ပ်များက ဘက်ထရီကုန်စေသည်"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"ချဲ့ခြင်း"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"နားကြားကိရိယာ"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"အများသုံးစွဲနိုင်မှုကို အသုံးပြုမှု"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"ဖန်သားပြင်"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> က ဘက်ထရီကို အသုံးပြုနေသည်"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"အက်ပ် ဒေါင်းလုဒ်လုပ်ရန်"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"SIM အသစ်ထည့်သွင်းလိုက်ပါသည်"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"၎င်းကိုတပ်ဆင်ရန် တို့ပါ"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"သင်၏ဒေသစံတော်ချိန် ပြောင်းသွားပါပြီ"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"သင်သည် ယခု <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) တွင် ရှိနေသည်"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"အချိန်သတ်မှတ်ရန်"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"ရက်စွဲ အတည်ပြုရန်"</string>
<string name="date_time_set" msgid="4603445265164486816">"သတ်မှတ်ရန်"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"လက်တစ်ဖက်သုံးမုဒ်"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ပိုမှိန်ခြင်း"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"နားကြားကိရိယာ"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ချိတ်ဆက်မထားပါ"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"ချိတ်ဆက်ထားသည်"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"သုံးနေသည်"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"ဖွင့်နေသည်"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"အသံခလုတ်များကို ဖိထားသည်။ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ဖွင့်လိုက်သည်။"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"အသံခလုတ်များကို ဖိထားသည်။ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ပိတ်လိုက်သည်။"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"အသံထိန်းခလုတ်များကို လွှတ်လိုက်ပါ။ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ဖွင့်ရန် အသံထိန်းခလုတ်နှစ်ခုစလုံးကို ၃ စက္ကန့်ကြာအောင် ထပ်နှိပ်ပါ။"</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"ဖုန်း၏မိုက်သို့ ပြောင်းမလား။"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"နားကြားကိရိယာ၏မိုက်သို့ ပြောင်းမလား။"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"အသံပိုကောင်းစေရန် (သို့) နားကြားကိရိယာ၏ ဘက်ထရီ နည်းနေပါက။ ခေါ်ဆိုနေစဉ်သာ သင့်မိုက်ကို ပြောင်းပေးသည်။"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"လက်လွတ်ခေါ်ဆိုခြင်းအတွက် နားကြားကိရိယာ၏ မိုက်ခရိုဖုန်းကို သုံးနိုင်သည်။ ခေါ်ဆိုနေစဉ်သာ သင့်မိုက်ကို ပြောင်းပေးသည်။"</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"ပြောင်းရန်"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ဆက်တင်များ"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g>ကို ထွက်ပစ်ပါတော့မည်..."</string>
@@ -1949,13 +1954,13 @@
<string name="data_saver_enable_title" msgid="7080620065745260137">"ဒေတာချွေတာမှုစနစ် ဖွင့်မလား။"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ဖွင့်ရန်"</string>
<string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{တစ်မိနစ်ကြာ ({formattedTime} အထိ)}other{# မိနစ်ကြာ ({formattedTime} အထိ)}}"</string>
- <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{1 မိနစ်ကြာ ({formattedTime} အထိ)}other{# မိနစ်ကြာ ({formattedTime} အထိ)}}"</string>
- <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{1 နာရီကြာ ({formattedTime} အထိ)}other{# နာရီကြာ ({formattedTime} အထိ)}}"</string>
- <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{1 နာရီကြာ ({formattedTime} အထိ)}other{# နာရီကြာ ({formattedTime} အထိ)}}"</string>
+ <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{၁ မိနစ်ကြာ ({formattedTime} အထိ)}other{# မိနစ်ကြာ ({formattedTime} အထိ)}}"</string>
+ <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{၁ နာရီကြာ ({formattedTime} အထိ)}other{# နာရီကြာ ({formattedTime} အထိ)}}"</string>
+ <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{၁ နာရီကြာ ({formattedTime} အထိ)}other{# နာရီကြာ ({formattedTime} အထိ)}}"</string>
<string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{တစ်မိနစ်ကြာ}other{# မိနစ်ကြာ}}"</string>
<string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{1 မိနစ်ကြာ}other{# မိနစ်ကြာ}}"</string>
- <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{1 နာရီကြာ}other{# နာရီကြာ}}"</string>
- <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{1 နာရီကြာ}other{# နာရီကြာ}}"</string>
+ <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{၁ နာရီကြာ}other{# နာရီကြာ}}"</string>
+ <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{1၁ နာရီကြာ}other{# နာရီကြာ}}"</string>
<string name="zen_mode_until_next_day" msgid="1403042784161725038">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> အထိ"</string>
<string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>အထိ"</string>
<string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> အထိ (လာမည့် နှိုးစက်)"</string>
@@ -2454,6 +2459,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"ဂြိုဟ်တုမှတစ်ဆင့် မက်ဆေ့ဂျ်ပို့ခြင်း သုံးမလား။"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"မိုဘိုင်း (သို့) Wi-Fi ကွန်ရက်မရှိဘဲ မက်ဆေ့ဂျ်များ ပို့နိုင်၊ လက်ခံနိုင်သည်"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ဖွင့်ရန်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index d21296d28696..c80a9605fcde 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Får ikke kontakt med mobilnettverket"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Prøv å endre foretrukket nettverk. Trykk for å endre."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Nødanrop er utilgjengelig"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Ikke vis dette igjen"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Du må være koblet til et mobilnettverk for å utføre nødanrop"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Varsler"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Viderekobling"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Nettverksvarsler"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Nettverk er tilgjengelig"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN-status"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Tid og tidssoner"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Varsler fra IT-administratoren din"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Varsler"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Butikkdemo"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"App kjører"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Apper bruker batteri"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Forstørring"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Høreapparat"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Bruk av Tilgjengelighet"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Skjerm"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> bruker batteri"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Last ned appen"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Et nytt SIM-kort er satt inn"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Konfigurer"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Tidssonen er endret"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Nå er du i <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Angi tidspunkt"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Angi dato"</string>
<string name="date_time_set" msgid="4603445265164486816">"Lagre"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Enhåndsmodus"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra dimmet"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Høreapparater"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Frakoblet"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Tilkoblet"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktiv"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Laster inn"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volumtastene holdes inne. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er slått på."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volumtastene holdes inne. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er slått av."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Slipp opp volumtastene. For å slå på <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, trykk og hold på begge volumtastene igjen i 3 sekunder."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Vil du bytte til mikrofonen i telefonen?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Vil du bytte til mikrofonen i høreapparatet?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"For bedre lyd eller hvis høreapparatet har lite batteri. Dette fører bare til at mikrofonen byttes under samtalen."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Du kan bruke mikrofonen i høreapparatet til å ringe håndfritt. Dette fører bare til at mikrofonen byttes under samtalen."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Bytt"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Innstillinger"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Logger av <xliff:g id="NAME">%1$s</xliff:g> …"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Av sikkerhetsgrunner er appinnholdet skjult for skjermdelingen"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Automatisk tilkoblet satellitt"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Du kan sende og motta meldinger uten mobil- eller wifi-nettverk"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Vil du bruke satellittmeldinger?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Send og motta meldinger uten mobil- eller wifi-nettverk"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Åpne Meldinger"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index c524a4847c69..bf7bbaf872be 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"मोबाइल नेटवर्कमाथि पहुँच राख्न सकिएन"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"रुचाइएको नेटवर्क परिवर्तन गरी हेर्नुहोस्‌। परिवर्तन गर्न ट्याप गर्नुहोस्‌।"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"आपत्‌कालीन कल सेवा अनुपलब्ध छ"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"फेरि नदेखाउनुहोस्"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"आपत्‌कालीन कलहरू गर्न मोबाइल नेटवर्क चाहिन्छ"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"अलर्टहरू"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"कल फर्वार्ड गर्ने सेवा"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"नेटवर्कका अलर्टहरू"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"नेटवर्क उपलब्ध छ"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN को स्थिति"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"समय र प्रामाणिक समय"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"तपाईंको IT प्रशासकबाट प्राप्त सतर्कताहरू"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"अलर्टहरू"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"खुद्रा बिक्री सम्बन्धी डेमो"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"एप चलिरहेको छ"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"एपहरूले ब्याट्री खपत गर्दै छन्"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"जुम इन गर्ने सुविधा"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"श्रवण यन्त्र"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"सर्वसुलभतासम्बन्धी सेवाहरूको प्रयोग"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"डिस्प्ले"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले ब्याट्री प्रयोग गर्दै छ"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"एप डाउनलोड गर्नुहोस्"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"नयाँ SIM घुसाइयो"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"यसलाई सेटअप गर्न ट्याप गर्नुहोस्"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"तपाईंको प्रामाणिक समय परिवर्तन गरिएको छ"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"तपाईं अहिले <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) मा हुनुहुन्छ"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"समय मिलाउनुहोस्"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"मिति मिलाउनुहोस्"</string>
<string name="date_time_set" msgid="4603445265164486816">"सेट गर्नुहोस्"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"एक हाते मोड"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"अझै मधुरो"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"हियरिङ डिभाइसहरू"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"डिस्कनेक्ट गरिएको"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"कनेक्ट गरिएको"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"सक्रिय"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"लोड हुँदै छ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"तपाईंले भोल्युम बटनहरू थिचिराख्नुभयो। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> अन भयो।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"तपाईंले भोल्युम बटनहरू थिचिराख्नुभयो। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> अफ भयो।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"भोल्युम बटनहरू थिच्न छाड्नुहोस्। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> अन गर्न दुवै भोल्युम बटन फेरि ३ सेकेन्डसम्म थिचिराख्नुहोस्।"</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"फोनको माइक प्रयोग गर्ने हो?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"श्रवण यन्त्रको माइक प्रयोग गर्ने हो?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"अझ राम्रो आवाज सुनाउन वा तपाईंको श्रवण यन्त्रको ब्याट्री कम भएका खण्डमा। यसले कल भइरहेका बेला मात्र तपाईंको माइक बदल्छ।"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"तपाईं ह्यान्ड्सफ्री तरिकाले कल गर्न आफ्नो श्रवण यन्त्रको माइक्रोफोन प्रयोग गर्न सक्नुहुन्छ। यसले कल भइरहेका बेला मात्र तपाईंको माइक बदल्छ।"</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"बदल्नुहोस्"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"सेटिङ"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"लग आउट गर्दै <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2454,6 +2459,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"स्याटलाइटमार्फत म्यासेज पठाउने सुविधा प्रयोग गर्ने हो?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"मोबाइल वा Wi-Fi नेटवर्कविनै म्यासेजहरू पठाउनुहोस् र प्राप्त गर्नुहोस्"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages खोल्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 609d642a5672..695a706dcdb4 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Kan mobiel netwerk niet bereiken"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Probeer een ander voorkeursnetwerk. Tik om te wijzigen."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Noodoproepen niet beschikbaar"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Niet meer tonen"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Voor noodoproepen is een mobiel netwerk vereist"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Meldingen"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Gesprek doorschakelen"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Netwerkmeldingen"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Netwerk beschikbaar"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN-status"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Tijd en tijdzones"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Meldingen van je IT-team"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Meldingen"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demo voor de detailhandel"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"App actief"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Apps die de batterij gebruiken"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Vergroting"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Hoortoestel"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Toegankelijkheidsgebruik"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Scherm"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> gebruikt de batterij"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"App downloaden"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Nieuwe simkaart geplaatst"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Tik om dit in te stellen"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Je tijdzone is gewijzigd"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Je bent nu in <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Tijd instellen"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Datum instellen"</string>
<string name="date_time_set" msgid="4603445265164486816">"Instellen"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Bediening met 1 hand"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dimmen"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hoortoestellen"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Verbinding verbroken"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Verbonden"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Actief"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Laden"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volumetoetsen ingedrukt gehouden. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> staat aan."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volumetoetsen ingedrukt gehouden. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> staat uit."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Laat de volumeknoppen los. Als je <xliff:g id="SERVICE_NAME">%1$s</xliff:g> wilt aanzetten, houd je beide volumeknoppen weer 3 seconden ingedrukt."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Wisselen naar microfoon van telefoon?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Wisselen naar microfoon van hoortoestel?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Voor beter geluid of als de batterij van je hoortoestel bijna leeg is. Hiermee wordt de microfoon alleen gewisseld tijdens het gesprek."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Je kunt de microfoon van je hoortoestel gebruiken om handsfree te bellen. Hiermee wordt de microfoon alleen gewisseld tijdens het gesprek."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Wisselen"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Instellingen"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> uitloggen…"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Vanwege beveiligingsrisico\'s is app-content verborgen voor scherm delen"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Automatisch verbonden met satelliet"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Je kunt berichten sturen en krijgen zonder een mobiel of wifi-netwerk"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Satellietberichten gebruiken?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Stuur en krijg berichten zonder mobiel of wifi-netwerk"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Berichten openen"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 51c4e3143586..de95a033ec20 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ମୋବାଇଲ୍‌ ନେଟ୍‌ୱର୍କ ମିଳୁନାହିଁ"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ନିଜ ପସନ୍ଦର ନେଟ୍‌ୱର୍କକୁ ଯିବାପାଇଁ ଚେଷ୍ଟା କରନ୍ତୁ। ବଦଳାଇବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ।"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ଜରୁରୀକାଳୀନ କଲ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"ପୁଣି ଦେଖାନ୍ତୁ ନାହିଁ"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"ଜରୁରୀକାଳୀନ କଲ କରିବା ପାଇଁ ଏକ ମୋବାଇଲ ନେଟୱାର୍କ ଆବଶ୍ୟକ"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"ଆଲର୍ଟ"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"କଲ୍‌ ଫରୱାର୍ଡିଂ"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"ନେଟୱର୍କ ଅଲର୍ଟ"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"ନେଟ୍‌ୱର୍କ ଉପଲବ୍ଧ ଅଛି"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN ସ୍ଥିତି"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"ସମୟ ଏବଂ ଟାଇମ ଜୋନ"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"ଆପଣଙ୍କର ଆଇଟି ଆଡ୍‌ମିନ୍‌ଙ୍କ ଠାରୁ ଆଲର୍ଟ"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"ଆଲର୍ଟ"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"ରିଟେଲ୍‌ ଡେମୋ"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"ଆପ୍‍ ଚାଲୁଛି"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"ଆପ୍‍ଗୁଡ଼ିକ ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କରିଥା\'ନ୍ତି"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"ମେଗ୍ନିଫିକେସନ"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"ଶ୍ରବଣ ଡିଭାଇସ"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"ଆକ୍ସେସିବିଲିଟୀ ବ୍ୟବହାର"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"ଡିସପ୍ଲେ"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବ୍ୟାଟେରୀ ବ୍ୟବହାର କରୁଛି"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"ଆପ୍‌ ଡାଉନଲୋଡ କରନ୍ତୁ"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"ନୂଆ SIM କାର୍ଡ ଭର୍ତ୍ତି କରାଗଲା"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"ଏହା ସେଟଅପ୍‌ କରିବା ପାଇଁ ଟାପ୍‌ କରନ୍ତୁ"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"ଆପଣଙ୍କର ଟାଇମ ଜୋନ ବଦଳିଛି"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"ଆପଣ ବର୍ତ୍ତମାନ <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)ରେ ଅଛନ୍ତି"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"ସମୟ ସେଟ୍ କରନ୍ତୁ"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"ତାରିଖ ସେଟ୍‍ କରନ୍ତୁ"</string>
<string name="date_time_set" msgid="4603445265164486816">"ସେଟ୍‍ କରନ୍ତୁ"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ଏକ-ହାତ ମୋଡ୍"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ଅତ୍ୟଧିକ ଡିମ"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"ଶ୍ରବଣ ଡିଭାଇସଗୁଡ଼ିକ"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ଡିସକନେକ୍ଟ କରାଯାଇଛି"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"କନେକ୍ଟ କରାଯାଇଛି"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"ସକ୍ରିୟ"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"ଲୋଡ ହେଉଛି"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ଭଲ୍ୟୁମ୍ କୀ\'ଗୁଡ଼ିକୁ ଧରି ରଖାଯାଇଛି। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ଚାଲୁ ହୋଇଛି।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ଭଲ୍ୟୁମ୍ କୀ\'ଗୁଡ଼ିକୁ ଧରି ରଖାଯାଇଛି। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ବନ୍ଦ ହୋଇଛି।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"ଭଲ୍ୟୁମ କୀ\'ଗୁଡ଼ିକୁ ରିଲିଜ କରନ୍ତୁ। <xliff:g id="SERVICE_NAME">%1$s</xliff:g>କୁ ଚାଲୁ କରିବା ପାଇଁ ଉଭୟ ଭଲ୍ୟୁମ କୀ\'କୁ ପୁଣି 3 ସେକେଣ୍ଡ ପାଇଁ ଦବାଇ ଧରି ରଖନ୍ତୁ।"</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"ଫୋନ ମାଇକକୁ ସୁଇଚ କରିବେ?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"ଶ୍ରବଣ ଯନ୍ତ୍ର ମାଇକକୁ ସୁଇଚ କରିବେ?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"ଭଲ ସାଉଣ୍ଡ ପାଇଁ କିମ୍ବା ଯଦି ଆପଣଙ୍କର ଶ୍ରବଣ ଯନ୍ତ୍ର ବ୍ୟାଟେରୀ କମ ଥିଲେ। କଲ ସମୟରେ ଏହା କେବଳ ଆପଣଙ୍କର ମାଇକ ସୁଇଚ କରିଥାଏ।"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"ହେଣ୍ଡସ-ଫ୍ରି କଲିଂ ପାଇଁ ଆପଣ ଆପଣଙ୍କର ଶ୍ରବଣ ଯନ୍ତ୍ର ମାଇକ୍ରୋଫୋନ ବ୍ୟବହାର କରିପାରିବେ। କଲ ସମୟରେ ଏହା କେବଳ ଆପଣଙ୍କର ମାଇକ ସୁଇଚ କରିଥାଏ।"</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"ସ୍ୱିଚ କରନ୍ତୁ"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ସେଟିଂସ"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g>ଙ୍କୁ ଲଗଆଉଟ୍‍ କରାଯାଉଛି…"</string>
@@ -2454,6 +2459,8 @@
<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">"ଏକ ମୋବାଇଲ କିମ୍ବା ୱାଇ-ଫାଇ ନେଟୱାର୍କ ବିନା ଆପଣ ମେସେଜ ପଠାଇପାରିବେ ଏବଂ ପାଇପାରିବେ"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"ସେଟେଲାଇଟ ମେସେଜିଂକୁ ବ୍ୟବହାର କରିବେ?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"ଏକ ମୋବାଇଲ କିମ୍ବା ୱାଇ-ଫାଇ ନେଟୱାର୍କ ବିନା ମେସେଜ ପଠାନ୍ତୁ ଏବଂ ପାଆନ୍ତୁ"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ଖୋଲନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 12f4e901ce07..4d4b10bb25db 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ਤਰਜੀਹੀ ਨੈੱਟਵਰਕ ਨੂੰ ਬਦਲ ਕੇ ਦੇਖੋ। ਬਦਲਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ਸੰਕਟਕਾਲੀਨ ਕਾਲਿੰਗ ਉਪਲਬਧ ਨਹੀਂ"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"ਦੁਬਾਰਾ ਨਾ ਦਿਖਾਓ"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"ਐਮਰਜੈਂਸੀ ਕਾਲਾਂ ਲਈ ਕਿਸੇ ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"ਅਲਰਟ"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ਕਾਲ ਫਾਰਵਰਡਿੰਗ"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"ਨੈੱਟਵਰਕ ਅਲਰਟ"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"ਨੈੱਟਵਰਕ ਉਪਲਬਧ ਹੈ"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN ਅਵਸਥਾ"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"ਸਮਾਂ ਅਤੇ ਸਮਾਂ ਖੇਤਰ"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"ਤੁਹਾਡੇ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅਲਰਟ"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"ਅਲਰਟ"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"ਪ੍ਰਚੂਨ ਸਟੋਰਾਂ ਲਈ ਡੈਮੋ"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"ਚੱਲ ਰਹੀ ਐਪ"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"ਬੈਟਰੀ ਦੀ ਖਪਤ ਕਰਨ ਵਾਲੀਆਂ ਐਪਾਂ"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"ਵੱਡਦਰਸ਼ੀਕਰਨ"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"ਸੁਣਨ ਵਾਲਾ ਡੀਵਾਈਸ"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"ਪਹੁੰਚਯੋਗਤਾ ਵਰਤੋਂ"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"ਡਿਸਪਲੇ"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਵੱਲੋਂ ਬੈਟਰੀ ਦੀ ਵਰਤੋਂ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"ਐਪ ਡਾਊਨਲੋਡ ਕਰੋ"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"ਨਵੀਂ SIM ਦਾਖਲ ਕੀਤੀ ਗਈ"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"ਇਸ ਨੂੰ ਸੈੱਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"ਤੁਹਾਡਾ ਸਮਾਂ ਖੇਤਰ ਬਦਲ ਗਿਆ ਹੈ"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"ਹੁਣ ਤੁਸੀਂ <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) ਵਿੱਚ ਹੋ"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"ਸਮਾਂ ਸੈੱਟ ਕਰੋ"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"ਤਾਰੀਖ ਸੈੱਟ ਕਰੋ"</string>
<string name="date_time_set" msgid="4603445265164486816">"ਸੈੱਟ ਕਰੋ"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ਇੱਕ ਹੱਥ ਮੋਡ"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ਜ਼ਿਆਦਾ ਘੱਟ ਚਮਕ"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"ਸੁਣਨ ਵਾਲੇ ਡੀਵਾਈਸ"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ਡਿਸਕਨੈਕਟ ਹੋ ਗਿਆ"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"ਕਨੈਕਟ ਹੈ"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"ਕਿਰਿਆਸ਼ੀਲ"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ਅਵਾਜ਼ੀ ਕੁੰਜੀਆਂ ਦਬਾ ਕੇ ਰੱਖੀਆਂ ਗਈਆਂ। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਗਿਆ।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ਅਵਾਜ਼ੀ ਕੁੰਜੀਆਂ ਦਬਾ ਕੇ ਰੱਖੀਆਂ ਗਈਆਂ। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"ਅਵਾਜ਼ ਕੁੰਜੀਆਂ ਨੂੰ ਛੱਡੋ। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਚਾਲੂ ਕਰਨ ਲਈ, ਦੋਵੇਂ ਅਵਾਜ਼ ਕੁੰਜੀਆਂ ਨੂੰ 3 ਸਕਿੰਟਾਂ ਲਈ ਦੁਬਾਰਾ ਦਬਾਈ ਰੱਖੋ।"</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"ਕੀ ਫ਼ੋਨ ਦੇ ਮਾਈਕ \'ਤੇ ਸਵਿੱਚ ਕਰਨਾ ਹੈ?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"ਕੀ ਸੁਣਨ ਦੇ ਸਾਧਨ ਦੇ ਮਾਈਕ \'ਤੇ ਸਵਿੱਚ ਕਰਨਾ ਹੈ?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"ਬਿਹਤਰ ਧੁਨੀ ਲਈ ਜਾਂ ਜੇ ਤੁਹਾਡੇ ਸੁਣਨ ਦੇ ਸਾਧਨ ਦੀ ਬੈਟਰੀ ਘੱਟ ਹੈ। ਇਹ ਸਿਰਫ਼ ਕਾਲ ਦੌਰਾਨ ਹੀ ਤੁਹਾਡੇ ਮਾਈਕ ਨੂੰ ਸਵਿੱਚ ਕਰਦਾ ਹੈ।"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"ਤੁਸੀਂ ਹੱਥ-ਰਹਿਤ ਕਾਲਿੰਗ ਲਈ ਆਪਣੇ ਸੁਣਨ ਦੇ ਸਾਧਨ ਦੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੇ ਹੋ। ਇਹ ਸਿਰਫ਼ ਕਾਲ ਦੌਰਾਨ ਹੀ ਤੁਹਾਡੇ ਮਾਈਕ ਨੂੰ ਸਵਿੱਚ ਕਰਦਾ ਹੈ।"</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"ਸਵਿੱਚ ਕਰੋ"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ਸੈਟਿੰਗਾਂ"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> ਨੂੰ ਲਾਗ-ਆਉਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ …"</string>
@@ -2454,6 +2459,8 @@
<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">"ਤੁਸੀਂ ਮੋਬਾਈਲ ਜਾਂ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਤੋਂ ਬਿਨਾਂ ਸੁਨੇਹੇ ਭੇਜ ਅਤੇ ਪ੍ਰਾਪਤ ਕਰ ਸਕਦੇ ਹੋ"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"ਕੀ ਸੈਟੇਲਾਈਟ ਸੁਨੇਹੇ ਦੀ ਵਰਤੋਂ ਕਰਨੀ ਹੈ?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"ਮੋਬਾਈਲ ਜਾਂ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਤੋਂ ਬਿਨਾਂ ਸੁਨੇਹੇ ਭੇਜੋ ਅਤੇ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ਐਪ ਖੋਲ੍ਹੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 113ffa37084e..810aa325e48a 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -89,8 +89,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Brak zasięgu sieci komórkowej"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Spróbuj zmienić preferowaną sieć. Kliknij, by zmienić."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Połączenia alarmowe są niedostępne"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Nie pokazuj ponownie"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Połączenia alarmowe wymagają sieci komórkowej"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alerty"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Przekierowanie połączeń"</string>
@@ -305,6 +304,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Alerty dotyczące sieci"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Sieć dostępna"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Stan sieci VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Godzina i strefy czasowe"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Alerty od administratora IT"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Alerty"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Tryb demo dla sklepów"</string>
@@ -312,6 +312,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Działa aplikacja"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Aplikacje zużywające baterię"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Powiększenie"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Urządzenie słuchowe"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Użycie ułatwień dostępu"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Wyświetlacz"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> zużywa baterię"</string>
@@ -1409,6 +1410,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Pobierz aplikację"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Włożono nową kartę SIM"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Kliknij, by skonfigurować"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Zmieniła się Twoja strefa czasowa"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Jesteś teraz w strefie <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Ustaw godzinę"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Ustaw datę"</string>
<string name="date_time_set" msgid="4603445265164486816">"Ustaw"</string>
@@ -1782,14 +1785,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Tryb jednej ręki"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Dodatkowe przyciemnienie"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Urządzenia słuchowe"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Rozłączone"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Połączone"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktywne"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Wczytuję"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Przytrzymano klawisze głośności. Usługa <xliff:g id="SERVICE_NAME">%1$s</xliff:g> została włączona."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Przytrzymano klawisze głośności. Usługa <xliff:g id="SERVICE_NAME">%1$s</xliff:g> została wyłączona."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Zwolnij przyciski głośności. Aby włączyć usługę <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, naciśnij i przytrzymaj oba przyciski głośności przez 3 sekundy."</string>
@@ -1800,6 +1799,12 @@
<string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Funkcja otworzy się, gdy następnym razem użyjesz tego skrótu. Przesuń 2 palcami z dołu ekranu i szybko je unieś."</string>
<string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Funkcja otworzy się, gdy następnym razem użyjesz tego skrótu. Przesuń 3 palcami z dołu ekranu i szybko je unieś."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Powiększenie"</string>
+ <string name="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Przełączyć na mikrofon w telefonie?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Przełączyć na mikrofon w aparacie słuchowym?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Skorzystaj z tej opcji, aby uzyskać lepszy dźwięk lub jeśli kończy się bateria w aparacie słuchowym. Mikrofon zostanie przełączony tylko na czas połączenia."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Możesz używać mikrofonu w aparacie słuchowym, aby dzwonić bez użycia rąk. Mikrofon zostanie przełączony tylko na czas połączenia."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Przełącz"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Ustawienia"</string>
<string name="user_switched" msgid="7249833311585228097">"Bieżący użytkownik: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Przełączam na użytkownika <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="7216437629179710359">"Wylogowuję użytkownika <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2456,6 +2461,7 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Ze względów bezpieczeństwa zawartość aplikacji jest niewidoczna podczas udostępniania ekranu"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Automatycznie połączono z satelitą"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Możesz wymieniać wiadomości bez dostępu do sieci komórkowej lub Wi-Fi"</string>
+ <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Przez satelitę możesz wysyłać i odbierać wiadomości oraz w ograniczonym stopniu korzystać z transmisji danych"</string>
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Przesyłać wiadomości przez satelitę?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Wysyłaj i odbieraj wiadomości bez sieci komórkowej czy Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Otwórz Wiadomości"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 2daa730b4a31..cc4b251c7713 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -88,8 +88,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Não foi possível acessar a rede móvel"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Tente alterar a rede preferencial. Toque para alterar."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Chamadas de emergência indisponíveis"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Não mostrar de novo"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"As chamadas de emergência exigem uma rede móvel"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertas"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Encaminhamento de chamada"</string>
@@ -304,6 +303,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Alertas de rede"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Rede disponível"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Status de VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Hora e fusos horários"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Alertas do administrador de TI"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Alertas"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demonstração na loja"</string>
@@ -311,6 +311,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"App em execução"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Apps que estão consumindo a bateria"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Ampliação"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Aparelho auditivo"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Uso de acessibilidade"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Tela"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está consumindo a bateria"</string>
@@ -1408,6 +1409,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Baixar o app"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Novo chip inserido"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Toque para configurar"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Seu fuso horário mudou"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Agora você está em <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Definir hora"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Definir data"</string>
<string name="date_time_set" msgid="4603445265164486816">"Definir"</string>
@@ -1779,16 +1782,12 @@
<string name="color_inversion_feature_name" msgid="2672824491933264951">"Inversão de cores"</string>
<string name="color_correction_feature_name" msgid="7975133554160979214">"Correção de cor"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo para uma mão"</string>
- <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Escurecer ainda mais a tela"</string>
+ <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Tela ainda mais escura"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Aparelhos auditivos"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desconectado"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Conectado"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Ativo"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Carregando"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume pressionadas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume pressionadas. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Solte as teclas de volume. Para ativar o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, toque e pressione as duas teclas de volume por três segundos."</string>
@@ -1799,6 +1798,12 @@
<string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"O recurso será aberto na próxima vez que você usar este atalho. Deslize com 2 dedos de baixo para cima na tela e solte rapidamente."</string>
<string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"O recurso será aberto na próxima vez que você usar este atalho. Deslize com 3 dedos de baixo para cima na tela e solte rapidamente."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Ampliação"</string>
+ <string name="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Trocar para o microfone do smartphone?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Trocar para o microfone do aparelho auditivo?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Para melhorar o som ou se a bateria do aparelho auditivo estiver fraca. A troca do microfone só será feita durante a ligação."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Você pode usar o microfone do aparelho auditivo para fazer ligações sem usar as mãos. A troca do microfone só será feita durante a ligação."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Trocar"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Configurações"</string>
<string name="user_switched" msgid="7249833311585228097">"Usuário atual <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Mudando para <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="7216437629179710359">"Desconectando <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2455,6 +2460,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo oculto no compartilhamento de tela por segurança"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Conectado automaticamente ao satélite"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Você pode enviar e receber mensagens sem um dispositivo móvel ou uma rede Wi-Fi"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Usar mensagens via satélite?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Enviar e receber mensagens sem uma rede móvel ou Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir o app Mensagens"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 5572de130221..af76e3f1ad03 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -88,8 +88,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Não é possível estabelecer ligação à rede móvel."</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Experimente alterar a rede preferida. Toque para alterar."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Chamadas de emergência indisponíveis"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Não mostrar novamente"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"As chamadas de emergência requerem uma rede móvel"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertas"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Reencaminhamento de chamadas"</string>
@@ -304,6 +303,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Alertas da rede"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Rede disponível"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Estado da VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Hora e fusos horários"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Alertas do seu administrador de TI"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Alertas"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demonstração para retalho"</string>
@@ -311,6 +311,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Aplicação em execução"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Apps que estão a consumir bateria"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Ampliação"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Dispositivo auditivo"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Utilização da acessibilidade"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Ecrã"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a consumir bateria."</string>
@@ -1408,6 +1409,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Transferir app"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Novo SIM inserido"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Toque para configurar"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"O seu fuso horário foi alterado"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Está agora em <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Definir hora"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Definir data"</string>
<string name="date_time_set" msgid="4603445265164486816">"Definir"</string>
@@ -1781,14 +1784,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo para uma mão"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Mais escuro"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Dispositivos auditivos"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desligado"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Ligado"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Ativo"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"A carregar"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas do volume premidas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume premidas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Solte as teclas de volume. Para ativar o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, prima sem soltar ambas as teclas de volume novamente durante 3 segundos."</string>
@@ -1799,6 +1798,12 @@
<string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"A funcionalidade vai ser aberta da próxima vez que usar este atalho. Deslize com 2 dedos a partir da parte inferior do ecrã e solte rapidamente."</string>
<string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"A funcionalidade vai ser aberta da próxima vez que usar este atalho. Deslize para cima com 3 dedos a partir da parte inferior do ecrã e solte rapidamente."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Ampliação"</string>
+ <string name="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Mudar para o microfone do telemóvel?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Mudar para o microfone do aparelho auditivo?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Para um som melhor ou se a bateria do aparelho auditivo estiver fraca. Esta ação apenas muda o microfone durante a chamada."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Pode usar o microfone do aparelho auditivo para chamadas mãos-livres. Esta ação apenas muda o microfone durante a chamada."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Mudar"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Definições"</string>
<string name="user_switched" msgid="7249833311585228097">"<xliff:g id="NAME">%1$s</xliff:g> do utilizador atual."</string>
<string name="user_switching_message" msgid="1912993630661332336">"A mudar para <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="7216437629179710359">"A terminar a sessão de <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2455,6 +2460,7 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo da app ocultado da partilha de ecrã por motivos de segurança"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Ligação de satélite estabelecida automaticamente"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Pode enviar e receber mensagens sem uma rede móvel ou Wi-Fi"</string>
+ <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Pode enviar e receber mensagens, e usar dados limitados, por satélite"</string>
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Quer usar as mensagens por satélite?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Envie e receba mensagens sem uma rede móvel ou Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Abre a app Mensagens"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 2daa730b4a31..cc4b251c7713 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -88,8 +88,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Não foi possível acessar a rede móvel"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Tente alterar a rede preferencial. Toque para alterar."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Chamadas de emergência indisponíveis"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Não mostrar de novo"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"As chamadas de emergência exigem uma rede móvel"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertas"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Encaminhamento de chamada"</string>
@@ -304,6 +303,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Alertas de rede"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Rede disponível"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Status de VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Hora e fusos horários"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Alertas do administrador de TI"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Alertas"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demonstração na loja"</string>
@@ -311,6 +311,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"App em execução"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Apps que estão consumindo a bateria"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Ampliação"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Aparelho auditivo"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Uso de acessibilidade"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Tela"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está consumindo a bateria"</string>
@@ -1408,6 +1409,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Baixar o app"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Novo chip inserido"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Toque para configurar"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Seu fuso horário mudou"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Agora você está em <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Definir hora"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Definir data"</string>
<string name="date_time_set" msgid="4603445265164486816">"Definir"</string>
@@ -1779,16 +1782,12 @@
<string name="color_inversion_feature_name" msgid="2672824491933264951">"Inversão de cores"</string>
<string name="color_correction_feature_name" msgid="7975133554160979214">"Correção de cor"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo para uma mão"</string>
- <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Escurecer ainda mais a tela"</string>
+ <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Tela ainda mais escura"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Aparelhos auditivos"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desconectado"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Conectado"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Ativo"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Carregando"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume pressionadas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume pressionadas. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Solte as teclas de volume. Para ativar o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, toque e pressione as duas teclas de volume por três segundos."</string>
@@ -1799,6 +1798,12 @@
<string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"O recurso será aberto na próxima vez que você usar este atalho. Deslize com 2 dedos de baixo para cima na tela e solte rapidamente."</string>
<string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"O recurso será aberto na próxima vez que você usar este atalho. Deslize com 3 dedos de baixo para cima na tela e solte rapidamente."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Ampliação"</string>
+ <string name="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Trocar para o microfone do smartphone?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Trocar para o microfone do aparelho auditivo?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Para melhorar o som ou se a bateria do aparelho auditivo estiver fraca. A troca do microfone só será feita durante a ligação."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Você pode usar o microfone do aparelho auditivo para fazer ligações sem usar as mãos. A troca do microfone só será feita durante a ligação."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Trocar"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Configurações"</string>
<string name="user_switched" msgid="7249833311585228097">"Usuário atual <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Mudando para <xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="7216437629179710359">"Desconectando <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2455,6 +2460,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo oculto no compartilhamento de tela por segurança"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Conectado automaticamente ao satélite"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Você pode enviar e receber mensagens sem um dispositivo móvel ou uma rede Wi-Fi"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Usar mensagens via satélite?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Enviar e receber mensagens sem uma rede móvel ou Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir o app Mensagens"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index cf0f771b190c..25b0471347c9 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -88,8 +88,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Nu se poate stabili conexiunea la rețeaua mobilă"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Încearcă să schimbi rețeaua preferată. Atinge pentru a schimba."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Apelurile de urgență nu sunt disponibile"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Nu mai afișa"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Apelurile de urgență necesită o rețea mobilă"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alerte"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Redirecționarea apelurilor"</string>
@@ -304,6 +303,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Alerte privind rețeaua"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Rețea disponibilă"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Stare VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Ora și fusurile orare"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Alerte de la administratorul IT"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Alerte"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demonstrație comercială"</string>
@@ -311,6 +311,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Aplicația rulează"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Aplicațiile consumă bateria"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Mărire"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Aparat auditiv"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Folosirea accesibilității"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Ecran"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> folosește bateria"</string>
@@ -1408,6 +1409,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Descarcă aplicația"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"S-a introdus un card SIM nou"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Atinge pentru a-l configura"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Fusul orar s-a schimbat"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Acum te afli în <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Setează ora"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Setează data"</string>
<string name="date_time_set" msgid="4603445265164486816">"Setează"</string>
@@ -1781,14 +1784,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modul cu o mână"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Luminozitate redusă suplimentar"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Aparate auditive"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Deconectat"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Conectat"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Activ"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Se încarcă"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"S-au apăsat lung tastele de volum. S-a activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"S-au apăsat lung tastele de volum. S-a dezactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Eliberează butoanele de volum. Pentru a activa <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, apasă lung pe ambele butoane de volum timp de trei secunde încă o dată."</string>
@@ -1799,6 +1798,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Comuți la microfonul telefonului?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Comuți la microfonul aparatului auditiv?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Pentru un sunet mai bun sau dacă bateria aparatului auditiv este descărcată. Astfel, microfonul pornește numai în timpul apelului."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Poți folosi microfonul aparatului auditiv pentru apelarea hands-free. Astfel, microfonul pornește numai în timpul apelului."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Schimbă"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Setări"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Se deconectează utilizatorul <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2455,6 +2460,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conținutul aplicației este ascuns de permiterea accesului la ecran din motive de securitate"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"S-a conectat automat la satelit"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Poți să trimiți și să primești mesaje fără o rețea mobilă sau Wi-Fi"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Folosești mesajele prin satelit?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Trimite și primește mesaje fără o rețea mobilă sau Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Deschide Mesaje"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 387cd338bb9c..1efa10593edc 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -89,8 +89,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Мобильная сеть недоступна"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Нажмите, чтобы выбрать другую сеть."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Экстренные вызовы недоступны"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Больше не показывать"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Для экстренных вызовов нужна мобильная сеть."</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Оповещения"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Переадресация вызовов"</string>
@@ -305,6 +304,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Оповещения сети"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Сеть доступна"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Статус VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Время и часовые пояса"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Уведомления от вашего администратора"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Уведомления"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Деморежим для магазина"</string>
@@ -312,6 +312,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Приложение активно"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Приложения, расходующие заряд"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Увеличение"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Слуховой аппарат"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Сервисы специальных возможностей"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Экран"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" расходует заряд"</string>
@@ -1409,6 +1410,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Скачать приложение"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Установлена новая SIM-карта"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Нажмите, чтобы настроить."</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Ваш часовой пояс изменился"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Новый часовой пояс: <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)."</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Настройка времени"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Настройка даты"</string>
<string name="date_time_set" msgid="4603445265164486816">"Установить"</string>
@@ -1782,14 +1785,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Режим управления одной рукой"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Дополнительное уменьшение яркости"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слуховые аппараты"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Отключено"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Подключено"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Активно"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Загрузка…"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Использован жест с кнопками регулировки громкости. Функция \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\" включена."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Использован жест с кнопками регулировки громкости. Функция \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\" отключена."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Отпустите кнопки громкости. Чтобы включить <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, нажмите и удерживайте обе кнопки регулировки громкости в течение трех секунд."</string>
@@ -1800,6 +1799,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Переключиться на микрофон телефона?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Переключиться на микрофон слухового аппарата?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Вы можете использовать микрофон телефона, если вас не устраивает качество звука или если у слухового аппарата низкий заряд батареи. Микрофон будет переключен только на время звонка."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Вы можете использовать микрофон слухового аппарата, когда разговариваете по телефону. Микрофон будет переключен только на время звонка."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Переключиться"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Настройки"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Выход из аккаунта <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2456,6 +2461,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Включить спутниковый обмен сообщениями?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Отправляйте и получайте сообщения без подключения к мобильной сети или Wi-Fi."</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Открыть Сообщения"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 9fd63e471962..57f89a230384 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ජංගම ජාලය වෙත ළඟා විය නොහැකිය"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"කැමති ජාලය වෙනස් කිරීමට උත්සාහ කරන්න. වෙනස් කිරීමට තට්ටු කරන්න."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"හදිසි ඇමතුම් ලබා ගත නොහැකිය"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"නැවතත් නොපෙන්වන්න"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"හදිසි ඇමතුම් සඳහා ජංගම ජාලයක් අවශ්‍ය වේ"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"ඇඟවීම්"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ඇමතුම ප්‍රතියොමු කිරීම"</string>
@@ -303,6 +302,8 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"ජාල ඇඟවීම්"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"ජාලය ලබා ගැනීමට හැකිය"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN තත්ත්වය"</string>
+ <!-- no translation found for notification_channel_system_time (1660313368058030441) -->
+ <skip />
<string name="notification_channel_device_admin" msgid="6384932669406095506">"ඔබේ තොරතුරු තාක්‍ෂණ පරිපාලක වෙතින් ඇඟවීම්"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"ඇඟවීම්"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"සිල්ලර ආදර්ශනය"</string>
@@ -310,6 +311,8 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"යෙදුම ධාවනය කරමින්"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"බැටරිය භාවිත කරන යෙදුම්"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"විශාලනය"</string>
+ <!-- no translation found for notification_channel_accessibility_hearing_device (7816963856388758952) -->
+ <skip />
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"ප්‍රවේශ්‍යතා භාවිතය"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"සංදර්ශකය"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> බැටරිය භාවිත කරයි"</string>
@@ -1407,6 +1410,10 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"යෙදුම බාගන්න"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"නව SIM ඇතුළු කරන්න"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"එය පිහිටුවීමට තට්ටු කරන්න"</string>
+ <!-- no translation found for time_zone_change_notification_title (5232503069219193218) -->
+ <skip />
+ <!-- no translation found for time_zone_change_notification_body (6135793674904665585) -->
+ <skip />
<string name="time_picker_dialog_title" msgid="9053376764985220821">"වේලාව සකසන්න"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"දිනය සැකසීම"</string>
<string name="date_time_set" msgid="4603445265164486816">"සකසන්න"</string>
@@ -1780,14 +1787,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"තනි අත් ප්‍රකාරය"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"තවත් අඳුරු"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"ශ්‍රවණ උපාංග"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"විසන්ධි විය"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"සම්බන්ධිතයි"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"සක්‍රිය"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"පූරණය වේ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"හඬ පරිමා යතුරු අල්ලා ගන්න <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්‍රියාත්මකයි."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"හඬ පරිමා යතුරු අල්ලා ගන්න <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්‍රියාවිරහිතයි."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"හඬ පරිමා යතුරු මුදා හරින්න. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> සක්‍රීය කිරීමට, හඬ පරිමා යතුරු දෙකම නැවත තත්පර 3ක් ඔබා අල්ලා සිටින්න."</string>
@@ -1798,6 +1801,18 @@
<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>
+ <!-- no translation found for hearing_device_switch_phone_mic_notification_title (6645178038359708836) -->
+ <skip />
+ <!-- no translation found for hearing_device_switch_hearing_mic_notification_title (4612074852145289569) -->
+ <skip />
+ <!-- no translation found for hearing_device_switch_phone_mic_notification_text (1332426273666077412) -->
+ <skip />
+ <!-- no translation found for hearing_device_switch_hearing_mic_notification_text (8288368365767284208) -->
+ <skip />
+ <!-- no translation found for hearing_device_notification_switch_button (3619524619430941300) -->
+ <skip />
+ <!-- no translation found for hearing_device_notification_settings_button (6673651052880279178) -->
+ <skip />
<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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> වරමින්…"</string>
@@ -2454,6 +2469,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"චන්ද්‍රිකා පණිවිඩ යැවීම භාවිතා කරන්න ද?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"ජංගම හෝ Wi-Fi ජාලයකින් තොරව පණිවිඩ යැවීම සහ ලැබීම"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages විවෘත කරන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 35283675c9ef..c50773d594a9 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -89,8 +89,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Nepodarilo sa pripojiť k mobilnej sieti"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Skúste zmeniť predvolenú sieť. Zmeníte ju klepnutím."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Tiesňové volania nie sú k dispozícii"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Nabudúce nezobrazovať"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Tiesňové volania vyžadujú mobilnú sieť"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Upozornenia"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Presmerovanie hovorov"</string>
@@ -305,6 +304,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Upozornenia týkajúce sa siete"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Sieť je k dispozícii"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Stav pripojenia VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Čas a časové pásma"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Upozornenia od vášho správcu IT"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Upozornenia"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Predajná ukážka"</string>
@@ -312,6 +312,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Aplikácia je spustená"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Aplikácie spotrebúvajúce batériu"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Zväčšenie"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Načúvacie zariadenie"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Využitie dostupnosti"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Obrazovka"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> používa batériu"</string>
@@ -1409,6 +1410,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Stiahnuť aplikáciu"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Bola vložená nová SIM karta"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Nastavte ju klepnutím"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Vaše časové pásmo sa zmenilo"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Teraz ste v oblasti <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Nastaviť čas"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Nastaviť dátum"</string>
<string name="date_time_set" msgid="4603445265164486816">"Nastaviť"</string>
@@ -1782,14 +1785,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Režim jednej ruky"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Mimoriadne stmavenie"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Načúvacie zariadenia"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Odpojené"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Pripojené"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktívne"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Načítava sa"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Pridržali ste tlačidlá hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je zapnutá."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Pridržali ste tlačidlá hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je vypnutá."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Uvoľnite tlačidlá hlasitosti. Ak chcete zapnúť službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, znova pridržte tri sekundy obe tlačidlá hlasitosti."</string>
@@ -1800,6 +1799,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Chcete prepnúť na mikrofón telefónu?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Chcete prepnúť na mikrofón načúvadla?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Keď chcete zlepšiť zvuk alebo ak je batéria načúvadla slabá. Týmto iba prepnete mikrofón počas hovoru."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Volať handsfree môžete pomocou mikrofónu načúvadla. Týmto iba prepnete mikrofón počas hovoru."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Prepnúť"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Nastavenia"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Prebieha odhlásenie používateľa <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2456,6 +2461,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Obsah aplikácie je z bezpečnostných dôvodov pri zdieľaní obrazovky skrytý"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Automaticky pripojené k satelitu"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Správy môžete odosielať a prijímať bez mobilnej siete či siete Wi-Fi"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Chcete používať správy cez satelit?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Odosielajte a prijímajte správy bez mobilnej siete či siete Wi‑Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvoriť Správy"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index af6c95c70db4..134ee9df3f3d 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -89,8 +89,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Mobilnega omrežja ni mogoče doseči"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Poskusite spremeniti prednostno omrežje. Dotaknite se, če ga želite spremeniti."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Klicanje v sili ni na voljo"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Ne prikaži več"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Za klice v sili potrebujete mobilno omrežje"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Opozorila"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Preusmerjanje klicev"</string>
@@ -305,6 +304,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Opozorila omrežja"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Omrežje je na voljo"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Stanje omrežja VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Ura in časovni pasovi"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Opozorila skrbnika za IT"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Opozorila"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Predstavitev za maloprodajo"</string>
@@ -312,6 +312,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Aplikacija se izvaja"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Aplikacije, ki porabljajo energijo baterije"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Povečava"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Slušni pripomoček"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Uporaba funkcij za dostopnost"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Zaslon"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> porablja energijo baterije"</string>
@@ -1409,6 +1410,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Prenos aplikacije"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Nova kartica SIM je vstavljena"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Dotaknite se za nastavitev"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Časovni pas se je spremenil"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Zdaj ste v časovnem pasu <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Nastavi uro"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Nastavi datum"</string>
<string name="date_time_set" msgid="4603445265164486816">"Nastavi"</string>
@@ -1782,14 +1785,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Enoročni način"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Zelo zatemnjen zaslon"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Slušni pripomočki"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Brez povezave"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Povezano"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktivno"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Nalaganje"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tipki za glasnost sta pridržani. Storitev <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je vklopljena."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tipki za glasnost sta pridržani. Storitev <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je izklopljena."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Spustite gumba za glasnost. Če želite vklopiti storitev <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, znova pritisnite in 3 sekunde pridržite oba gumba za glasnost."</string>
@@ -1800,6 +1799,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Želite preklopiti na mikrofon telefona?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Želite preklopiti na mikrofon za slušni aparat?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Za boljši zvok ali pri skoraj prazni bateriji slušnega aparata. S tem preklopite mikrofon samo med klicem."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Mikrofon za slušni aparat lahko uporabljate za prostoročno klicanje. S tem preklopite mikrofon samo med klicem."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Preklopi"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Nastavitve"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Odjavljanje uporabnika <xliff:g id="NAME">%1$s</xliff:g> …"</string>
@@ -2456,6 +2461,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Pri deljenju zaslona je vsebina aplikacije skrita zaradi varnosti"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Samodejno vzpostavljena povezava s satelitom"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Sporočila SMS lahko pošiljate in prejemate brez mobilnega omrežja ali omrežja Wi-Fi"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Želite uporabiti satelitsko pošiljanje sporočil?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Pošiljanje in prejemanje sporočil brez mobilnega omrežja ali omrežja Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Odpri Sporočila"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index d8fdb9a30d56..0a87e39e16df 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Rrjeti celular është i paarritshëm"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Provo të ndryshosh rrjetin e preferuar. Trokit për ta ndryshuar."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Telefonatat e urgjencës nuk ofrohen"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Mos e shfaq më"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Telefonatat e urgjencës kërkojnë një rrjet celular"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Sinjalizimet"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Transferimi i telefonatave"</string>
@@ -303,6 +302,8 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Sinjalizimet e rrjetit"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Ka rrjet të disponueshëm"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Statusi i VPN-së"</string>
+ <!-- no translation found for notification_channel_system_time (1660313368058030441) -->
+ <skip />
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Sinjalizimet nga administratori i teknologjisë së informacionit"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Sinjalizimet"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demonstrimi i shitjes me pakicë"</string>
@@ -310,6 +311,8 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Aplikacioni është në ekzekutim"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Aplikacionet që konsumojnë baterinë"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Zmadhimi"</string>
+ <!-- no translation found for notification_channel_accessibility_hearing_device (7816963856388758952) -->
+ <skip />
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Përdorimi i qasshmërisë"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Ekrani"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> po përdor baterinë"</string>
@@ -1407,6 +1410,10 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Shkarko aplikacionin"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Është futur kartë e re SIM"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Trokit për ta konfiguruar"</string>
+ <!-- no translation found for time_zone_change_notification_title (5232503069219193218) -->
+ <skip />
+ <!-- no translation found for time_zone_change_notification_body (6135793674904665585) -->
+ <skip />
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Cakto kohën"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Vendos datën"</string>
<string name="date_time_set" msgid="4603445265164486816">"Cakto"</string>
@@ -1780,14 +1787,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modaliteti i përdorimit me një dorë"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Shumë më i zbehtë"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Pajisjet e dëgjimit"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Shkëputur"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Lidhur"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktive"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Po ngarkohet"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tastet e volumit të mbajtura shtypur. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> i aktivizuar."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tastet e volumit të mbajtura shtypur. U çaktivizua \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\"."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Lësho tastet e volumit. Për të aktivizuar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, shtyp dhe mbaj shtypur të dy tastet e volumit sërish për 3 sekonda."</string>
@@ -1798,6 +1801,18 @@
<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>
+ <!-- no translation found for hearing_device_switch_phone_mic_notification_title (6645178038359708836) -->
+ <skip />
+ <!-- no translation found for hearing_device_switch_hearing_mic_notification_title (4612074852145289569) -->
+ <skip />
+ <!-- no translation found for hearing_device_switch_phone_mic_notification_text (1332426273666077412) -->
+ <skip />
+ <!-- no translation found for hearing_device_switch_hearing_mic_notification_text (8288368365767284208) -->
+ <skip />
+ <!-- no translation found for hearing_device_notification_switch_button (3619524619430941300) -->
+ <skip />
+ <!-- no translation found for hearing_device_notification_settings_button (6673651052880279178) -->
+ <skip />
<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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> po del…"</string>
@@ -2454,6 +2469,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Përmbajtja e aplikacionit është fshehur nga ndarja e ekranit për arsye sigurie"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"U lidh automatikisht me satelitin"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Mund të dërgosh dhe të marrësh mesazhe pa një rrjet celular apo rrjet Wi-Fi"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Të përdoret shkëmbimi i mesazheve nëpërmjet satelitit?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Dërgo dhe merr mesazhe pa një rrjet celular ose Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Hap \"Mesazhet\""</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 146855e730bb..33150dc3c3c2 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -88,8 +88,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Повезивање са мобилном мрежом није успело"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Пробајте да промените жељену мрежу. Додирните да бисте променили."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Хитни позиви нису доступни"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Не приказуј поново"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Хитни позиви захтевају мобилну мрежу"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Упозорења"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Преусмеравање позива"</string>
@@ -304,6 +303,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Обавештења у вези са мрежом"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Мрежа је доступна"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Статус VPN-а"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Време и временске зоне"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Обавештења од ИТ администратора"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Упозорења"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Режим демонстрације за малопродајне објекте"</string>
@@ -311,6 +311,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Активна апликација"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Апликације које троше батерију"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Увећање"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Слушни апарат"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Коришћење Приступачности"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Екран"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> користи батерију"</string>
@@ -1408,6 +1409,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Преузмите апликацију"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Нова SIM картица је уметнута"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Додирните за подешавање"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Временска зона је промењена"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Сада сте у временској зони <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Подесите време"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Подешавање датума"</string>
<string name="date_time_set" msgid="4603445265164486816">"Подеси"</string>
@@ -1781,14 +1784,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Режим једном руком"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Додатно затамни"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слушни апарати"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Веза је прекинута"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Повезано"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Активно"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Учитава се"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Држали сте тастере за јачину звука. Услуга <xliff:g id="SERVICE_NAME">%1$s</xliff:g> је укључена."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Држали сте тастере за јачину звука. Услуга <xliff:g id="SERVICE_NAME">%1$s</xliff:g> је искључена."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Пустите тастере за јачину звука. Да бисте укључили <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, поново притисните и задржите оба тастера за јачину звука 3 секунде."</string>
@@ -1799,6 +1798,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Желите да пређете на микрофон телефона?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Желите да пређете на микрофон слушног апарата?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"За бољи звук или ако је батерија слушног апарата скоро празна. Тиме се микрофон мења само током позива."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Можете да користите микрофон слушног апарата за хендсфри позивање. Тиме се микрофон мења само током позива."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Промени"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Подешавања"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Одјављује се <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2455,6 +2460,8 @@
<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">"Можете да шаљете и примате поруке без мобилне или WiFi мреже"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Желите да користите сателитску размену порука?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Шаљите и примајте поруке без мобилне или WiFi мреже"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Отвори Messages"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index ecb3c79cff45..ceb0fe1d6654 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Det går inte att nå mobilnätverket"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Testa att byta föredraget nätverk. Tryck om du vill ändra."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Det går inte att ringa nödsamtal"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Visa inte igen"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Mobilnätverk krävs för att ringa nödsamtal"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Aviseringar"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Vidarekoppla samtal"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Nätverksvarningar"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Nätverk tillgängligt"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN-status"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Tid och tidszoner"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Aviseringar från IT-administratören"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Varningar"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demo för återförsäljare"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"App körs"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Appar som drar batteri"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Förstoring"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Hörhjälpmedel"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Tillgänglighetsanvändning"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Skärm"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> drar batteri"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Ladda ned appen"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Nytt SIM-kort har satts in"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Tryck om du vill konfigurera"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Din tidszon har ändrats"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Du befinner dig nu i <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Ange tid"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Ange datum"</string>
<string name="date_time_set" msgid="4603445265164486816">"Ställ in"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Enhandsläge"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extradimmat"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hörhjälpmedel"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Frånkopplad"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Ansluten"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktiv"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Läser in"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volymknapparna har tryckts ned. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> har aktiverats."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volymknapparna har tryckts ned. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> har inaktiverats."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Släpp volymknapparna. Du kan aktivera <xliff:g id="SERVICE_NAME">%1$s</xliff:g> genom att hålla båda volymknapparna nedtryckta i tre sekunder igen."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Vill du byta till telefonens mikrofon?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Vill du byta till hörapparatens mikrofon?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"För bättre ljud eller om hörapparaten har lite batteri. Detta byter bara mikrofon under samtalet."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Du kan använda hörapparatens mikrofon för handsfree-samtal. Detta byter bara mikrofon under samtalet."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Byt"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Inställningar"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Loggar ut <xliff:g id="NAME">%1$s</xliff:g> …"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Av säkerhetsskäl döljs appinnehållet vid skärmdelning"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Automatiskt ansluten till satellit"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Du kan skicka och ta emot meddelanden utan mobil- eller wifi-nätverk"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Vill du använda satellitmeddelanden?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Skicka och ta emot meddelanden utan ett mobil- eller wifi-nätverk"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Öppna Messages"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 98c973140a65..58d71817a078 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Imeshindwa kufikia mtandao wa simu"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Jaribu kutumia mtandao unaopendelea. Gusa ili ubadilishe."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Huduma ya kupiga simu za dharura haipatikani"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Usionyeshe Tena"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Huduma ya kupiga simu za dharura inahitaji mtandao wa simu"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Arifa"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Kupeleka simu kwenye namba nyingine"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Arifa za mtandao"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Mtandao unapatikana"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Hali ya VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Saa na saa za maeneo"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Arifa kutoka kwa Msimamizi wako wa TEHAMA"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Arifa"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Onyesho la duka la rejareja"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Programu inaendelea kutekelezwa"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Programu zinazotumia betri"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Ukuzaji"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Vifaa vya kusikilizia"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Matumizi ya zana za ufikivu"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Skrini"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> inatumia betri"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Pakua programu"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"SIM mpya imewekwa"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Gusa ili uiweke"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Saa za eneo lako zimebadilika"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Sasa unatumia saa za eneo za <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Weka saa"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Weka tarehe"</string>
<string name="date_time_set" msgid="4603445265164486816">"Weka"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Hali ya kutumia kwa mkono mmoja"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Kipunguza mwangaza zaidi"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Vifaa vya kusaidia kusikia"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Haijaunganishwa"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Imeunganishwa"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Inatumika"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Inapakia"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Vitufe vya sauti vilivyoshikiliwa. Umewasha <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Vitufe vya sauti vimeshikiliwa. Umezima <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Achilia vitufe vya sauti. Ili uwashe <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, bonyeza na ushikilie tena vitufe vyote vya sauti kwa sekunde 3."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Ungependa kubadilisha utumie maikrofoni ya simu?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Ungependa kubadilisha utumie maikrofoni ya visaidizi vya kusikia?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Kwa sauti bora au iwapo chaji ya betri ya visaidizi vyako vya kusikia imepungua. Hali hii hubadilisha maikrofoni yako tu wakati unapiga simu."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Unaweza kutumia maikrofoni ya visaidizi vyako vya kusikia ili kupiga simu bila kugusa. Hali hii hubadilisha maikrofoni yako tu wakati unapiga simu."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Badilisha"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Mipangilio"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Inamwondoa <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Maudhui ya programu yamefichwa ili yasionekane kwenye skrini ya pamoja kwa sababu za kiusalama"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Imeunganishwa kiotomatiki na satelaiti"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Unaweza kutuma na kupokea ujumbe bila mtandao wa simu au Wi-Fi"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Ungependa kutuma ujumbe kupitia setilaiti?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Tuma na upokee ujumbe bila kutumia mtandao wa simu wala Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Fungua Programu ya Messages"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index f8b2bbc35b7d..59668bbff71d 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"மொபைல் நெட்வொர்க் கிடைக்கவில்லை"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"விருப்ப நெட்வொர்க்கை மாற்றவும். மாற்ற, தட்டவும்."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"அவசர அழைப்பைச் செய்ய முடியாது"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"மீண்டும் காட்டாதே"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"அவசர அழைப்புகளுக்கு மொபைல் நெட்வொர்க் தேவை"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"விழிப்பூட்டல்கள்"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"அழைப்பு திருப்பிவிடுதல்"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"நெட்வொர்க் விழிப்பூட்டல்கள்"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"நெட்வொர்க் உள்ளது"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN நிலை"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"நேரம் மற்றும் நேர மண்டலங்கள்"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"IT நிர்வாகியிடம் இருந்து வரும் விழிப்பூட்டல்கள்"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"விழிப்பூட்டல்கள்"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"விற்பனையாளர் டெமோ"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"ஆப்ஸ் இயங்குகிறது"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"பேட்டரியைப் பயன்படுத்தும் ஆப்ஸ்"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"பெரிதாக்கல்"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"செவித்துணைக் கருவி"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"அணுகல்தன்மை உபயோகம்"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"டிஸ்ப்ளே"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் பேட்டரியைப் பயன்படுத்துகிறது"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"பயன்பாட்டைப் பதிவிறக்கு"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"புதிய சிம் செருகப்பட்டது"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"அமைக்க, தட்டவும்"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"உங்கள் நேர மண்டலம் மாற்றப்பட்டது"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"நீங்கள் இப்போது இருப்பது: <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"நேரத்தை அமை"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"தேதியை அமை"</string>
<string name="date_time_set" msgid="4603445265164486816">"அமை"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ஒற்றைக் கைப் பயன்முறை"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"மிகக் குறைவான வெளிச்சம்"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"செவித்துணைக் கருவிகள்"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"இணைப்புநீக்கப்பட்டது"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"இணைக்கப்பட்டுள்ளது"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"செயலில் உள்ளது"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"ஏற்றுகிறது"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ஒலியளவுக்கான விசைகளைப் பிடித்திருந்தீர்கள். <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ஆன் செய்யப்பட்டது."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ஒலியளவுக்கான விசைகளைப் பிடித்திருந்தீர்கள். <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ஆஃப் செய்யப்பட்டது."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"ஒலியளவு பட்டன்களை அழுத்துவதை நிறுத்துங்கள். <xliff:g id="SERVICE_NAME">%1$s</xliff:g> சேவையை இயக்க, ஒலியளவு பட்டன்கள் இரண்டையும் 3 வினாடிகளுக்கு மீண்டும் அழுத்திப் பிடிக்கவும்."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"ஃபோன் மைக்கிற்கு மாறவா?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"செவித்துணைக் கருவியின் மைக்கிற்கு மாறவா?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"மேம்பட்ட ஒலிக்கோ செவித்துணைக் கருவியில் பேட்டரி குறைவாக இருந்தாலோ. அழைப்பின்போது உங்கள் மைக்கை மட்டுமே இது மாற்றுகிறது."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"கைகளைப் பயன்படுத்தாமல் அழைக்க உங்கள் செவித்துணைக் கருவியின் மைக்ரோஃபோனைப் பயன்படுத்தலாம். அழைப்பின்போது உங்கள் மைக்கை மட்டுமே இது மாற்றுகிறது."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"மாற்று"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"அமைப்புகள்"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> வெளியேறுகிறார்…"</string>
@@ -2454,6 +2459,8 @@
<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">"மொபைல்/வைஃபை நெட்வொர்க் இல்லாமல் நீங்கள் மெசேஜ்களை அனுப்பலாம் பெறலாம்"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"சாட்டிலைட் மெசேஜிங்கைப் பயன்படுத்தவா?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"மொபைல்/வைஃபை நெட்வொர்க் இல்லாமல் மெசேஜ்களை அனுப்பலாம், பெறலாம்"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ஆப்ஸைத் திறக்கவும்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index bcd2865173d4..6285d776cfab 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"మొబైల్ నెట్‌వర్క్ అందుబాటులో లేదు"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ప్రాధాన్య నెట్‌వర్క్‌ను మార్చుకోవడానికి ప్రయత్నించండి. మార్చడానికి నొక్కండి."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"అత్యవసర కాలింగ్ అందుబాటులో లేదు"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"మళ్లీ చూపవద్దు"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"ఎమర్జెన్సీ కాల్స్‌కు మొబైల్ నెట్‌వర్క్ అవసరమవుతుంది"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"అలర్ట్‌లు"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"కాల్ ఫార్వార్డింగ్"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"నెట్‌వర్క్ హెచ్చరికలు"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"నెట్‌వర్క్ అందుబాటులో ఉంది"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN స్టేటస్‌"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"టైమ్, టైమ్ జోన్‌లు"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"మీ IT నిర్వాహకుల నుండి వచ్చే హెచ్చరికలు"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"అలర్ట్‌లు"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"రిటైల్ డెమో"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"యాప్ అమలవుతోంది"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"బ్యాటరీని ఉపయోగిస్తున్న యాప్‌లు"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"మ్యాగ్నిఫికేషన్"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"వినికిడి పరికరం"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"యాక్సెసిబిలిటీ వినియోగం"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"డిస్‌ప్లే చేయండి"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> బ్యాటరీని ఉపయోగిస్తోంది"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"యాప్‌ని డౌన్‌లోడ్ చేయి"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"కొత్త SIM చొప్పించారు"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"దీన్ని సెటప్ చేయడానికి నొక్కండి"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"మీ టైమ్ జోన్ మారింది"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"మీరు ఇప్పుడు <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g>‌లో (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) ఉన్నారు"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"సమయాన్ని సెట్ చేయండి"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"తేదీని సెట్ చేయండి"</string>
<string name="date_time_set" msgid="4603445265164486816">"సెట్ చేయి"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"వన్-హ్యాండెడ్ మోడ్"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ఎక్స్‌ట్రా డిమ్"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"వినికిడి పరికరాలు"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"డిస్‌కనెక్ట్ అయింది"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"కనెక్ట్ చేయబడింది"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"యాక్టివ్"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"లోడ్ అవుతోంది"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"వాల్యూమ్ కీలు నొక్కి ఉంచబడ్డాయి. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆన్ చేయబడింది"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"వాల్యూమ్ కీలు నొక్కి ఉంచబడ్డాయి. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆఫ్ చేయబడింది"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"వాల్యూమ్ కీలను రిలీజ్ చేయండి. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>‌ను ఆన్ చేయడానికి, రెండు వాల్యూమ్ కీలను మళ్లీ 3 సెకన్ల పాటు నొక్కి పట్టుకోండి."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"ఫోన్ మైక్‌కు మారాలా?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"వినికిడి పరికరం మైక్‌కు మారాలా?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"మెరుగైన సౌండ్ కోసం లేదా మీ వినికిడి పరికరం బ్యాటరీ తక్కువగా ఉన్నప్పుడు. ఇది కాల్ సమయంలో మాత్రమే మీ మైక్‌ను మారుస్తుంది."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"హ్యాండ్స్-ఫ్రీ కాలింగ్ కోసం మీరు మీ వినికిడి పరికరాన్ని ఉపయోగించవచ్చు. ఇది కాల్ సమయంలో మాత్రమే మీ మైక్‌ను మారుస్తుంది."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"మారండి"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"సెట్టింగ్‌లు"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g>ని లాగ్ అవుట్ చేస్తోంది…"</string>
@@ -2454,6 +2459,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"శాటిలైట్ మెసేజింగ్‌ను ఉపయోగించాలనుకుంటున్నారా?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"మొబైల్ లేదా Wi-Fi నెట్‌వర్క్ లేకుండా మెసేజ్‌లను పంపండి, స్వీకరించండి"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messagesను తెరవండి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 0e66e371f722..557286128053 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"เชื่อมต่อเครือข่ายมือถือไม่ได้"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ลองเปลี่ยนเครือข่ายที่ต้องการ แตะเพื่อเปลี่ยน"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"โทรหาหมายเลขฉุกเฉินไม่ได้"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"ไม่ต้องแสดงอีก"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"การโทรหาหมายเลขฉุกเฉินต้องใช้เครือข่ายมือถือ"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"การแจ้งเตือน"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"การโอนสาย"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"การแจ้งเตือนเครือข่าย"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"มีเครือข่ายพร้อมใช้งาน"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"สถานะ VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"เวลาและเขตเวลา"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"การแจ้งเตือนจากผู้ดูแลระบบไอทีของคุณ"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"การแจ้งเตือน"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"การสาธิตสำหรับผู้ค้าปลีก"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"แอปที่ทำงานอยู่"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"แอปหลายแอปกำลังใช้แบตเตอรี่"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"การขยาย"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"เครื่องช่วยฟัง"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"การใช้งานการช่วยเหลือพิเศษ"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"จอแสดงผล"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังใช้แบตเตอรี่"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"ดาวน์โหลดแอป"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"ใส่ซิมใหม่แล้ว"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"แตะเพื่อตั้งค่า"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"เขตเวลามีการเปลี่ยนแปลง"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"ตอนนี้คุณอยู่ในเขตเวลา <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"ตั้งเวลา"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"ตั้งวันที่"</string>
<string name="date_time_set" msgid="4603445265164486816">"ตั้งค่า"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"โหมดมือเดียว"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"หรี่แสงเพิ่มเติม"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"เครื่องช่วยฟัง"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"เลิกเชื่อมต่อแล้ว"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"เชื่อมต่อแล้ว"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"ใช้งานอยู่"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"กำลังโหลด"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"กดปุ่มปรับระดับเสียงค้างไว้แล้ว เปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"กดปุ่มปรับระดับเสียงค้างไว้แล้ว ปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"ปล่อยปุ่มปรับระดับเสียง หากต้องการเปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ให้กดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มค้างไว้อีกครั้งเป็นเวลา 3 วินาที"</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"เปลี่ยนไปใช้ไมโครโฟนของโทรศัพท์ไหม"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"เปลี่ยนไปใช้ไมโครโฟนของเครื่องช่วยฟังไหม"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"เพื่อให้เสียงดีขึ้นหรือในกรณีที่แบตเตอรี่ของเครื่องช่วยฟังใกล้หมด การดำเนินการนี้เพียงแค่เปลี่ยนไมโครโฟนระหว่างการโทรเท่านั้น"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"คุณใช้ไมโครโฟนของเครื่องช่วยฟังเพื่อโทรแบบแฮนด์ฟรีได้ การดำเนินการนี้เพียงแค่เปลี่ยนไมโครโฟนระหว่างการโทรเท่านั้น"</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"เปลี่ยน"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"การตั้งค่า"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"กำลังออกจากระบบ <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2454,6 +2459,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"ใช้การรับส่งข้อความผ่านดาวเทียมไหม"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"รับและส่งข้อความโดยไม่ต้องใช้เครือข่ายมือถือหรือ Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"เปิด Messages"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 0ab4fb2901b6..44832c87a3a7 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Hindi makakonekta sa mobile network"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Subukang baguhin ang gustong network. I-tap para baguhin."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Hindi available ang pang-emergency na pagtawag"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Huwag Ipakita Ulit"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Kailangan ng mobile network para sa mga emergency na tawag"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Mga Alerto"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Pagpasa ng tawag"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Mga alerto sa network"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Available ang network"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Status ng VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Oras at mga time zone"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Mga alerto mula sa iyong IT admin"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Mga Alerto"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Retail demo"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Tumatakbo ang app"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Mga app na kumokonsumo ng baterya"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Pag-magnify"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Hearing device"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Paggamit sa pagiging accessible"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Display"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"Gumagamit ng baterya ang <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
@@ -880,7 +881,7 @@
<item msgid="7740243458912727194">"Mobile"</item>
<item msgid="8526146065496663766">"Trabaho"</item>
<item msgid="8150904584178569699">"Fax sa Trabaho"</item>
- <item msgid="4537253139152229577">"Fax sa Tahanan"</item>
+ <item msgid="4537253139152229577">"Home Fax"</item>
<item msgid="6751245029698664340">"Pager"</item>
<item msgid="1692790665884224905">"Iba pa"</item>
<item msgid="6216981255272016212">"Custom"</item>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"I-download ang app"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Nakalagay na ang bagong SIM"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"I-tap upang i-set up ito"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Nagbago ang iyong time zone"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Nasa <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) ka na ngayon."</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Magtakda ng oras"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Itakda ang petsa"</string>
<string name="date_time_set" msgid="4603445265164486816">"Itakda"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"One-Hand mode"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dim"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Mga hearing device"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Nadiskonekta"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Nakakonekta"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktibo"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Naglo-load"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Pinindot nang matagal ang volume keys. Na-on ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Pinindot nang matagal ang volume keys. Na-off ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Bitawan ang mga volume key. Para i-on ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, muling pindutin nang matagal ang dalawang volume key sa loob ng 3 segundo."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Lumipat sa mikropono ng telepono?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Lumipat sa mikropono ng hearing aid?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Para sa mas malinaw na tunog o kung paubos na ang baterya ng iyong hearing aid. Inililipat lang nito ang iyong mikropono habang nasa tawag ka."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Puwede mong gamitin ang mikropono ng iyong hearing aid para sa hands-free na pagtawag. Inililipat lang nito ang iyong mikropono habang nasa tawag ka."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Lumipat"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Mga Setting"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Nila-log out si <xliff:g id="NAME">%1$s</xliff:g>..."</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Nakatago ang content ng app mula sa pagbabahagi ng screen para sa seguridad"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Awtomatikong nakakonekta sa satellite"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Puwede kang magpadala at tumanggap ng mga mensahe nang walang mobile o Wi-Fi network"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Gumamit ng satellite messaging?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Magpadala at tumanggap ng mga mensahe nang walang mobile o Wi-Fi network"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Buksan ang Messages"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 78ce9d4d3ae5..1a8d373a2aa2 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Mobil ağa erişilemiyor"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Tercih edilen ağı değiştirmeyi deneyin. Değiştirmek için dokunun."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Acil durum çağrısı kullanılamaz"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Bir daha gösterme"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Acil durum aramaları için mobil ağ gereklidir"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Uyarılar"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Çağrı yönlendirme"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Ağ uyarıları"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Ağ mevcut"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN durumu"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Saat ve saat dilimleri"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"IT yöneticinizden uyarılar"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Uyarılar"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Mağaza demo"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Uygulama çalışıyor"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Pil kullanan uygulamalar"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Büyütme"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"İşitme cihazı"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Erişilebilirlik kullanımı"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Ekran"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> pil kullanıyor"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Uygulama indir"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Yeni SIM kart takıldı"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Kurmak için dokunun"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Saat diliminiz değişti"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Artık <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) saat dilimindesiniz"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Saati ayarlayın"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Tarihi ayarlayın"</string>
<string name="date_time_set" msgid="4603445265164486816">"Ayarla"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Tek El modu"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra loş"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"İşitme cihazları"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Bağlı değil"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Bağlı"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Etkin"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Yükleniyor"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ses tuşlarını basılı tuttunuz. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> açıldı."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ses tuşlarını basılı tuttunuz. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kapatıldı."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Ses seviyesi tuşlarını bırakın. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini etkinleştirmek için her iki ses seviyesi tuşuna yeniden basıp 3 saniye boyunca basılı tutun."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Telefon mikrofonuna geçilsin mi?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"İşitme cihazı mikrofonuna geçilsin mi?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Daha iyi ses kalitesi için veya işitme cihazınızın pili azaldığında Bu işlem yalnızca görüşme sırasında mikrofonunuzu değiştirir."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Eller serbest modunda arama yapmak için işitme cihazı mikrofonunu kullanabilirsiniz. Bu işlem yalnızca görüşme sırasında mikrofonunuzu değiştirir."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Geçiş yap"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Ayarlar"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> hesabından çıkış yapılıyor…"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Uygulama içerikleri, güvenlik nedeniyle ekran paylaşımında gizlendi"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Uyduya otomatik olarak bağlandı"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Mobil veya kablosuz ağa bağlı olmadan mesaj alıp gönderebilirsiniz"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Uydu üzerinden mesajlaşma kullanılsın mı?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Mobil veya kablosuz ağ kullanmadan mesaj gönderip alın"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Mesajlar\'ı aç"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index a98fda433f8f..5e6f9ec90037 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -89,8 +89,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Не вдається під’єднатися до мобільної мережі"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Спробуйте змінити вибрану мережу. Торкніться, щоб це зробити."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Екстрені виклики недоступні"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Більше не показувати"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Щоб здійснювати екстрені виклики, потрібне з’єднання з мобільною мережею"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Сповіщення"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Переадресація виклику"</string>
@@ -305,6 +304,8 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Сповіщення мережі"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Мережа доступна"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Статус мережі VPN"</string>
+ <!-- no translation found for notification_channel_system_time (1660313368058030441) -->
+ <skip />
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Сповіщення від ІТ-адміністратора"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Сповіщення"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Демо-режим для роздрібної торгівлі"</string>
@@ -312,6 +313,8 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Працює додаток"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Додатки, що використовують заряд акумулятора"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Збільшення"</string>
+ <!-- no translation found for notification_channel_accessibility_hearing_device (7816963856388758952) -->
+ <skip />
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Використання спеціальних можливостей"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Дисплей"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> використовує заряд акумулятора"</string>
@@ -1409,6 +1412,10 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Завантажити додаток"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Вставлено нову SIM-карту"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Торкніться, щоб налаштувати"</string>
+ <!-- no translation found for time_zone_change_notification_title (5232503069219193218) -->
+ <skip />
+ <!-- no translation found for time_zone_change_notification_body (6135793674904665585) -->
+ <skip />
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Установити час"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Установити дату"</string>
<string name="date_time_set" msgid="4603445265164486816">"Застосувати"</string>
@@ -1782,14 +1789,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Режим керування однією рукою"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Додаткове зменшення яскравості"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слухові апарати"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Від’єднано"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Під’єднано"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Активний"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Завантаження"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Утримано клавіші гучності. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> увімкнено."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Утримано клавіші гучності. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> вимкнено."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Відпустіть клавіші гучності. Щоб увімкнути сервіс <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, натисніть і втримуйте обидві клавіші гучності протягом 3 секунд."</string>
@@ -1800,6 +1803,18 @@
<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>
+ <!-- no translation found for hearing_device_switch_phone_mic_notification_title (6645178038359708836) -->
+ <skip />
+ <!-- no translation found for hearing_device_switch_hearing_mic_notification_title (4612074852145289569) -->
+ <skip />
+ <!-- no translation found for hearing_device_switch_phone_mic_notification_text (1332426273666077412) -->
+ <skip />
+ <!-- no translation found for hearing_device_switch_hearing_mic_notification_text (8288368365767284208) -->
+ <skip />
+ <!-- no translation found for hearing_device_notification_switch_button (3619524619430941300) -->
+ <skip />
+ <!-- no translation found for hearing_device_notification_settings_button (6673651052880279178) -->
+ <skip />
<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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Вихід з облікового запису користувача <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2456,6 +2471,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Скористатися супутниковим обміном повідомленнями?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Надсилайте й отримуйте текстові повідомлення без мобільної мережі або Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Відкрийте Повідомлення"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 0a0047422a74..7ddd7cb8a02a 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"موبائل نیٹ ورک تک رسائی نہیں ہو سکتی"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ترجیحی نیٹ ورک تبدیل کر کے دیکھیں۔ تبدیل کرنے کے لیے تھپتھپائیں۔"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ایمرجنسی کالنگ دستیاب نہیں ہے"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"دوبارہ نہ دکھائیں"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"ہنگامی کالز کو موبائل نیٹ ورک کی ضرورت ہے"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"الرٹس"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"کال فارورڈنگ"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"نیٹ ورک الرٹس"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"نیٹ ورک دستیاب ہے"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"‏VPN اسٹیٹس"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"وقت اور ٹائم زونز"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"‏آپ کے IT منتظم کی جانب سے الرٹس"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"الرٹس"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"ریٹیل ڈیمو"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"ایپ چل رہی ہے"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"ایپس بیٹری خرچ کر رہی ہیں"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"میگنیفکیشن"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"آلہ سماعت"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"ایکسیسبیلٹی کا استعمال"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"ڈسپلے"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> بیٹری کا استعمال کر رہی ہے"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"ایپ ڈاؤن لوڈ کریں"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"‏نئی SIM داخل ہو گئی"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"اسے سیٹ اپ کرنے کیلئے تھپتھپائیں"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"آپ کا ٹائم زون تبدیل ہو گیا"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"آپ اب <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) میں ہیں"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"وقت سیٹ کریں"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"تاریخ سیٹ کریں"</string>
<string name="date_time_set" msgid="4603445265164486816">"سیٹ کریں"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ایک ہاتھ کی وضع"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"اضافی مدھم"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"سماعتی آلات"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"غیر منسلک ہے"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"منسلک ہے"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"فعال"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"لوڈ ہو رہا ہے"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"والیوم کی کلیدوں کو دبائے رکھا گیا۔ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> آن ہے۔"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"والیوم کی کلیدوں کو دبائے رکھا گیا۔ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> آف ہے۔"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"والیوم کی کلیدوں کو ریلیز کریں <xliff:g id="SERVICE_NAME">%1$s</xliff:g> کو آن کرنے کے لیے، والیوم کی دونوں کلیدوں کو دوبارہ 3 سیکنڈ تک چھوئیں اور دبائے رکھیں۔"</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"فون کے مائیک پر سوئچ کریں؟"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"سماعتی آلہ کے مائیک پر سوئچ کریں؟"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"بہتر آواز کے لیے یا اگر آپ کے سماعتی آلہ کی بیٹری کم ہے۔ یہ صرف کال کے دوران آپ کا مائیک سوئچ کرتا ہے۔"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"آپ ہینڈز فری کالنگ کے لیے اپنا سماعتی آلہ مائیکروفون استعمال کر سکتے ہیں۔ یہ صرف کال کے دوران آپ کا مائیک سوئچ کرتا ہے۔"</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"سوئچ کریں"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ترتیبات"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> لاگ آؤٹ ہو رہا ہے…"</string>
@@ -1974,7 +1979,7 @@
<string name="zen_mode_implicit_activated" msgid="2634285680776672994">"آن ہے"</string>
<string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"آف ہے"</string>
<string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">"، "</string>
- <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
+ <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"‪<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
<string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> تا <xliff:g id="END">%2$s</xliff:g>"</string>
<string name="zen_mode_trigger_summary_combined" msgid="6492381546327807669">"<xliff:g id="DAYS">%1$s</xliff:g>، <xliff:g id="TIMES">%2$s</xliff:g>"</string>
<string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"کوئی بھی کیلنڈر"</string>
@@ -2454,6 +2459,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"سیٹلائٹ پیغام رسانی کا استعمال کریں؟"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"‏موبائل یا Wi-Fi نیٹ ورک کے بغیر پیغامات بھیجیں اور موصول کریں"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"پیغامات ایپ کو کھولیں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 2f158f411a47..c1697953eb53 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Mobil tarmoqqa ulanib bo‘lmadi"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Tarmoq turini almashtiring. Almashtirish uchun bosing."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Favqulodda chaqiruv ishlamayapti"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Boshqa koʻrsatilmasin"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Favqulodda chaqiruvlar uchun mobil tarmoq zarur"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Ogohlantirishlar"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Chaqiruvlarni uzatish"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Tarmoqqa oid bildirgilar"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Tarmoq mavjud"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN holati"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Vaqt va vaqt mintaqalari"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Administratordan xabarlar"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Ogohlantirishlar"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demo rejim"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Ilova faol"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Batareya quvvatini sarflayotgan ilovalar"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Kattalashtirish"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Eshitish qurilmasi"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Qulayliklar ishlatilishi"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Displey"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi batareya quvvatini sarflamoqda"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Ilovani yuklab olish"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Yangi SIM karta solindi"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Sozlash uchun bosing"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Vaqt mintaqangiz oʻzgardi"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Endi bu yerdasiz: <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Vaqtni o‘rnatish"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Sanani kiritish"</string>
<string name="date_time_set" msgid="4603445265164486816">"O‘rnatish"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Ixcham rejim"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Juda xira"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Eshitish qurilmalari"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Uzildi"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Ulandi"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Faol"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Yuklanmoqda"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tovush tugmalari bosib turildi. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> yoqildi."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tovush tugmalari bosib turildi. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> faolsizlantirildi."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Tovush tugmalarini qoʻyib yuboring. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmatini yoqish uchun ikkala tovush tugmasini 3 soniya bosib turing."</string>
@@ -1798,6 +1797,12 @@
<string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Keyingi safar shu buyruqdan foydalanganingizda funksiya ochiladi. Ekranning pastidan 2 barmoq bilan tepaga suring va darhol qoʻyib yuboring."</string>
<string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Keyingi safar shu buyruqdan foydalanganingizda funksiya ochiladi. Ekranning pastidan 3 barmoq bilan tepaga suring va darhol qoʻyib yuboring."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Kattalashtirish"</string>
+ <string name="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Telefon mikrofoniga almashtirilsinmi?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Eshitish moslamasi mikrofoniga almashtirilsinmi?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Tovush yaxshilanishi uchun yoki eshitish moslamasi batareyasi quvvati kam boʻlsa. Bu faqat chaqiruv paytida mikrofonni almashtiradi."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Garniturali chaqiruv uchun eshitish moslamasi mikrofonidan foydalanish mumkin. Bu faqat chaqiruv paytida mikrofonni almashtiradi."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Almashtirish"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Sozlamalar"</string>
<string name="user_switched" msgid="7249833311585228097">"Joriy foydalanuvchi <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Bunga almashilmoqda: <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> hisobidan chiqilmoqda…"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Ekran namoyishida xavfsizlik maqsadida ilova kontenti berkitildi"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Sputnikka avtomatik ulandi"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Mobil yoki Wi-Fi tarmoqsiz xabarlarni yuborishingiz va qabul qilishingiz mumkin"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Sputnik orqali xabarlashuv ishlatilsinmi?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Mobil yoki Wi-Fi tarmoq blan aloqa yoʻqligida xabar yuboring va qabul qiling"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Xabarlar ilovasini ochish"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index adb3e023d59a..11b57703d339 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Không thể kết nối với mạng di động"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Hãy thử thay đổi mạng ưu tiên. Nhấn để thay đổi."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Không có dịch vụ gọi khẩn cấp"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Không hiện lại"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Cần có mạng di động để thực hiện các cuộc gọi khẩn cấp"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Thông báo"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Chuyển tiếp cuộc gọi"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Cảnh báo mạng"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Có mạng"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Trạng thái VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Thời gian và múi giờ"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Thông báo từ quản trị viên CNTT của bạn"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Cảnh báo"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Giới thiệu bán lẻ"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Ứng dụng đang chạy"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Các ứng dụng tiêu thụ pin"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Phóng to"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Thiết bị trợ thính"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Việc sử dụng tính năng hỗ trợ tiếp cận"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Hiển thị"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang sử dụng pin"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Tải xuống ứng dụng"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Đã lắp SIM mới"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Nhấn để thiết lập"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Múi giờ của bạn đã thay đổi"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Bạn đang ở múi giờ <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Đặt giờ"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Đặt ngày"</string>
<string name="date_time_set" msgid="4603445265164486816">"Đặt"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Chế độ một tay"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Siêu tối"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Thiết bị trợ thính"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Đã ngắt kết nối"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Đã kết nối"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Đang hoạt động"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Đang tải"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Bạn đã giữ các phím âm lượng. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> đã bật."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Bạn đã giữ các phím âm lượng. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> đã tắt."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Thả phím âm lượng. Để bật <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, hãy nhấn và giữ cả 2 phím âm lượng trong 3 giây một lần nữa."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Chuyển sang micrô trên điện thoại?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Chuyển sang micrô của thiết bị trợ thính?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Để có âm thanh tốt hơn hoặc nếu thiết bị trợ thính của bạn sắp hết pin. Thao tác này chỉ chuyển micrô của bạn trong cuộc gọi."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Bạn có thể sử dụng micrô của thiết bị trợ thính để gọi điện mà không cần dùng tay. Thao tác này chỉ chuyển micrô của bạn trong cuộc gọi."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Chuyển"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Cài đặt"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Đang đăng xuất <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Nội dung ứng dụng bị ẩn khỏi tính năng chia sẻ màn hình vì lý do bảo mật"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Đã tự động kết nối với vệ tinh"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Bạn có thể gửi và nhận tin nhắn mà không cần có mạng di động hoặc mạng Wi-Fi"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Sử dụng tính năng nhắn tin qua vệ tinh?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Gửi và nhận tin nhắn mà không cần mạng di động hoặc Wi-Fi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Mở ứng dụng Tin nhắn"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index dd90e25114d8..4a38b933b000 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"无法连接到移动网络"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"请尝试更改首选网络。点按即可更改。"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"无法使用紧急呼救服务"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"不再显示"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"紧急呼叫需要使用移动网络"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"提醒"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"来电转接"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"网络提醒"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"有可用的网络"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN 状态"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"时间和时区"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"您的 IT 管理员发来的提醒"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"提醒"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"零售演示模式"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"应用正在运行中"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"消耗电量的应用"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"放大功能"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"助听装置"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"无障碍功能使用情况"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"显示屏"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g>正在消耗电量"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"下载应用"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"已插入新 SIM 卡"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"点按即可进行设置"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"您的时区已更改"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"您现在位于<xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"设置时间"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"设置日期"</string>
<string name="date_time_set" msgid="4603445265164486816">"设置"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"单手模式"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"极暗"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"助听装置"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"已断开连接"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"已连接"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"活跃"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"正在加载"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"已按住音量键。<xliff:g id="SERVICE_NAME">%1$s</xliff:g>已开启。"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"已按住音量键。<xliff:g id="SERVICE_NAME">%1$s</xliff:g>已关闭。"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"松开音量键。如要启用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>,请再次同时按住两个音量键 3 秒。"</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"要切换为手机麦克风吗?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"要切换为助听器麦克风吗?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"可改善音质,或在助听器电池电量不足时使用。此操作只会切换通话期间的麦克风。"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"您可以使用助听器麦克风进行免提通话。此操作只会切换通话期间的麦克风。"</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"切换"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"设置"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"正在将<xliff:g id="NAME">%1$s</xliff:g>退出账号…"</string>
@@ -2454,6 +2459,8 @@
<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">"您无需使用移动网络或 WLAN 网络便能收发消息"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"使用卫星消息功能?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"即使没有移动网络或 WLAN 网络,也能收发消息"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"打开“信息”应用"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index d34ed3d68dbc..cd428895c4d0 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"無法連線至流動網絡"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"請嘗試變更偏好的網絡。輕按即可變更。"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"無法撥打緊急電話"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"不要再顯示"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"撥打緊急電話需要使用流動網絡"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"通知"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"來電轉駁"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"網絡通知"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"有可用的網絡"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN 狀態"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"時間和時區"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"來自 IT 管理員的通知"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"通知"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"零售示範"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"應用程式正在執行"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"耗用電量的應用程式"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"放大"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"助聽器"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"無障礙功能使用情況"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"顯示屏"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在使用電量"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"下載應用程式"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"已插入新的 SIM 卡"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"輕按即可設定"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"你的時區已變更"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"你現在處於 <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"設定時間"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"日期設定"</string>
<string name="date_time_set" msgid="4603445265164486816">"設定"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"單手模式"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"超暗"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"助聽器"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"已中斷連線"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"已連線"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"運作中"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"正在載入"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"已按住音量鍵。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> 已開啟。"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"已按住音量鍵。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> 已關閉。"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"鬆開音量鍵。如果要開 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>,請同時㩒住兩個音量鍵 3 秒。"</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"要切換至手機麥克風嗎?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"要切換至助聽器麥克風嗎?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"可改善音質,也在助聽器電量不足時適用。此操作只會切換通話期間的麥克風。"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"你可使用助聽器麥克風進行免提通話。此操作只會切換通話期間的麥克風。"</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"切換"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"設定"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"正在登出 <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2454,6 +2459,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"要使用衛星訊息嗎?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"在沒有流動網絡或 Wi-Fi 網絡的情況下收發短訊"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"開啟「訊息」"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 09d1a7b4e1ce..c8ae6793a4e3 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"無法連上行動網路"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"請嘗試變更偏好的網路。輕觸即可變更。"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"無法撥打緊急電話"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"不要再顯示"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"撥打緊急電話需要使用行動網路"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"快訊"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"來電轉接"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"網路警示"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"有可用的網路"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"VPN 狀態"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"時間和時區"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"來自 IT 管理員的快訊"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"快訊"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"零售商展示模式"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"應用程式執行中"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"正在耗用電量的應用程式"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"放大"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"助聽器"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"無障礙功能使用情形"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"螢幕"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在耗用電量"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"下載應用程式"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"已插入新的 SIM 卡"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"輕觸這裡即可進行設定"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"時區已變更"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"現在位於<xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"設定時間"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"日期設定"</string>
<string name="date_time_set" msgid="4603445265164486816">"設定"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"單手模式"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"超暗"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"助聽器"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"連線中斷"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"已連線"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"運作中"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"載入中"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"已按住音量鍵。「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」已開啟。"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"已按住音量鍵。「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」已關閉。"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"放開音量鍵。如要開啟 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>,請同時按住音量調高鍵和調低鍵 3 秒。"</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"要切換到手機麥克風嗎?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"要切換到助聽器麥克風嗎?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"可享更好的音質,或在助聽器電量過低時使用。麥克風只會在通話期間切換。"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"免持通話時,可以使用助聽器麥克風。麥克風只會在通話期間切換。"</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"切換"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"設定"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"正在將<xliff:g id="NAME">%1$s</xliff:g>登出帳戶…"</string>
@@ -2454,6 +2459,8 @@
<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>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"要使用衛星訊息功能嗎?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"即使沒有行動或 Wi-Fi 網路,還是可以收發訊息"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"開啟「訊息」應用程式"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index cfc060ac4bab..7658189f3f55 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -87,8 +87,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Ayikwazi ukufinyelela kunethiwekhi yeselula"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Zama ukushintsha inethiwekhi encanyelwayo. Thepha ukuze ushintshe."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Ukushaya okuphuthumayo akutholakali"</string>
- <!-- no translation found for emergency_calling_do_not_show_again (5034171343309733068) -->
- <skip />
+ <string name="emergency_calling_do_not_show_again" msgid="5034171343309733068">"Ungaphindi Ubonise Futhi"</string>
<string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Amakholi aphuthumayo adinga inethiwekhi yeselula"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Izexwayiso"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Ukudlulisa ikholi"</string>
@@ -303,6 +302,7 @@
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Izexwayiso zenethiwekhi"</string>
<string name="notification_channel_network_available" msgid="6083697929214165169">"Inethiwekhi iyatholakala"</string>
<string name="notification_channel_vpn" msgid="1628529026203808999">"Isimo se-VPN"</string>
+ <string name="notification_channel_system_time" msgid="1660313368058030441">"Isikhathi nezoni yesikhathi"</string>
<string name="notification_channel_device_admin" msgid="6384932669406095506">"Izxwayiso kusuka kumlawuli wakho we-IT"</string>
<string name="notification_channel_alerts" msgid="5070241039583668427">"Izexwayiso"</string>
<string name="notification_channel_retail_mode" msgid="3732239154256431213">"Idemo yokuthenga"</string>
@@ -310,6 +310,7 @@
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Uhlelo loksuebenza olusebenzayo"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Izinhlelo zokusebenza ezidla ibhethri"</string>
<string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Ukukhuliswa"</string>
+ <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Insizakuzwa"</string>
<string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Ukusetshenziswa kokufinyeleleka"</string>
<string name="notification_channel_display" msgid="6905032605735615090">"Bonisa"</string>
<string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> isebenzisa ibhethri"</string>
@@ -1407,6 +1408,8 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Landa uhlelo lokusebenza"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Kufakwe i-SIM entsha"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Thepha ukuze uyisethe"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Izoni yakho yesikhathi ishintshile"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Manje sewuku-<xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Hlela isikhathi"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"Setha idethi"</string>
<string name="date_time_set" msgid="4603445265164486816">"Hlela"</string>
@@ -1780,14 +1783,10 @@
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Imodi yesandla esisodwa"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ukufiphaza okwengeziwe"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Amadivayizi okuzwa"</string>
- <!-- no translation found for hearing_device_status_disconnected (497547752953543832) -->
- <skip />
- <!-- no translation found for hearing_device_status_connected (2149385149669918764) -->
- <skip />
- <!-- no translation found for hearing_device_status_active (4770378695482566032) -->
- <skip />
- <!-- no translation found for hearing_device_status_loading (5717083847663109747) -->
- <skip />
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Inqamukile"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"Ixhunyiwe"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"Kuyasebenza"</string>
+ <string name="hearing_device_status_loading" msgid="5717083847663109747">"Iyalayisha"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ubambe okhiye bevolumu. I-<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ivuliwe."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ubambe okhiye bevolumu. I-<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ivaliwe."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Khipha okhiye bevolumu. Ukuze uvule i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>, cindezela bese ubamba bobabili okhiye bevolumu futhi imizuzwana emi-3."</string>
@@ -1798,6 +1797,12 @@
<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="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Shintshela kumakrofoni yefoni?"</string>
+ <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Shintshela kumakrofoni yomshini wendlebe?"</string>
+ <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Ukuze uthole umsindo ongcono noma uma ibhethri lakho lomshini wendlebe liphansi. Lokhu kushintsha kuphela imakrofoni yakho ngesikhathi sekholi."</string>
+ <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Ungasebenzisa imakrofoni yakho yomshini wendlebe ekufoneni ngehands-free. Lokhu kushintsha kuphela imakrofoni yakho ngesikhathi sekholi."</string>
+ <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Shintsha"</string>
+ <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Amasethingi"</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>
<string name="user_logging_out_message" msgid="7216437629179710359">"Iyaphuma <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -2454,6 +2459,8 @@
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Okuqukethwe kwe-app kufihliwe kusuka ekwabelaneni kwesikrini ngokuvikelwa"</string>
<string name="satellite_notification_title" msgid="4026338973463121526">"Ixhumeke ngokuzenzakalelayo kusathelayithi"</string>
<string name="satellite_notification_summary" msgid="5207364139430767162">"Ungathumela futhi wamukele imilayezo ngaphandle kwenethiwekhi yeselula noma ye-Wi-Fi"</string>
+ <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) -->
+ <skip />
<string name="satellite_notification_manual_title" msgid="1097504441849466279">"Sebenzisa ukuthumela umyalezo ngesethelayithi?"</string>
<string name="satellite_notification_manual_summary" msgid="901206289846283445">"Thumela futhi wamukele imilayezo ngaphandle kwenethiwekhi yeselula noma yeWiFi"</string>
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Vula Imilayezo"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8372aecf0d27..bd1d3033165e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2737,7 +2737,7 @@
The default is true. -->
<attr name="windowIsFrameRatePowerSavingsBalanced" format="boolean"/>
- <!-- Flag indicating whether this window would opt-out the edge-to-edge enforcement.
+ <!-- Flag indicating whether this window would opt out the edge-to-edge enforcement.
<p>If this is false, the edge-to-edge enforcement will be applied to the window if it
belongs to an app targeting
@@ -2757,8 +2757,9 @@
The Configuration will be stable regardless of the system insets change.
</ul>
- <p>If this is true, the edge-to-edge enforcement won't be applied. However, this
- attribute will be deprecated and disabled in a future SDK level.
+ <p>If this is true, the edge-to-edge enforcement won't be applied. But if the window
+ belongs to an app targeting {@link android.os.Build.VERSION_CODES#BAKLAVA BAKLAVA} or
+ above, this attribute is ignored and the enforcement is applied regardless.
<p>This is false by default. -->
<attr name="windowOptOutEdgeToEdgeEnforcement" format="boolean"/>
@@ -7590,7 +7591,7 @@
<!-- Minimum required drawing width. The drawing width refers to the width after
the original segments have been adjusted for the neighboring Points and gaps. This is
enforced by stretching the segments that are too short. -->
- <attr name="minWidth" format="dimension" />
+ <attr name="minWidth" />
<!-- Height of the solid segments. -->
<attr name="height" />
<!-- Height of the faded segments. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index e14cffd72b0c..ec1be83dcae6 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3156,6 +3156,16 @@
with admin privileges and admin privileges can be granted/revoked from existing users. -->
<bool name="config_enableMultipleAdmins">false</bool>
+ <!-- Whether to start stopped users before their scheduled alarms. If set to true, users will be
+ started in background before the alarm time so that it can go off. If false, alarms of
+ stopped users will not go off and users will remain stopped. -->
+ <bool name="config_allowAlarmsOnStoppedUsers">true</bool>
+
+ <!-- Whether notification is shown to foreground user when alarm/timer goes off on background
+ user. If set to true, foreground user will receive a notification with ability to mute
+ sound or switch user. If false, system notification will not be shown. -->
+ <bool name="config_showNotificationForBackgroundUserAlarms">true</bool>
+
<!-- Whether there is a communal profile which should always be running.
Only relevant for Headless System User Mode (HSUM) devices. -->
<bool name="config_omnipresentCommunalUser">false</bool>
@@ -5225,10 +5235,6 @@
<!-- Whether or not swipe up gesture's opt-in setting is available on this device -->
<bool name="config_swipe_up_gesture_setting_available">true</bool>
- <!-- Applications which are disabled unless matching a particular sku -->
- <string-array name="config_disableApksUnlessMatchedSku_apk_list" translatable="false" />
- <string-array name="config_disableApkUnlessMatchedSku_skus_list" translatable="false" />
-
<!-- Whether or not we should show the option to show battery percentage -->
<bool name="config_battery_percentage_setting_available">true</bool>
@@ -7313,4 +7319,8 @@
<!-- Whether the device supports Wi-Fi USD feature. -->
<bool name="config_deviceSupportsWifiUsd">false</bool>
+
+ <!-- Array containing the notification assistant service adjustments that are not supported by
+ default on this device-->
+ <string-array translatable="false" name="config_notificationDefaultUnsupportedAdjustments" />
</resources>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index e82992b91783..3f657541eb28 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -159,15 +159,15 @@
<!-- @FlaggedApi(android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE_MODULE)
@hide @SystemApi -->
- <public name="config_defaultOnDeviceIntelligenceService"></public>
+ <public name="config_defaultOnDeviceIntelligenceService" />
<!-- @FlaggedApi(android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE_MODULE)
@hide @SystemApi -->
- <public name="config_defaultOnDeviceSandboxedInferenceService"></public>
+ <public name="config_defaultOnDeviceSandboxedInferenceService" />
<!-- @FlaggedApi(android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE_MODULE)
@hide @SystemApi -->
- <public name="config_defaultOnDeviceIntelligenceDeviceConfigNamespace"></public>
+ <public name="config_defaultOnDeviceIntelligenceDeviceConfigNamespace" />
</staging-public-group>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 68008e57094d..77cc6868bd58 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -366,6 +366,8 @@
<java-symbol type="bool" name="config_canSwitchToHeadlessSystemUser"/>
<java-symbol type="bool" name="config_enableMultiUserUI"/>
<java-symbol type="bool" name="config_enableMultipleAdmins"/>
+ <java-symbol type="bool" name="config_allowAlarmsOnStoppedUsers"/>
+ <java-symbol type="bool" name="config_showNotificationForBackgroundUserAlarms"/>
<java-symbol type="bool" name="config_bootToHeadlessSystemUser"/>
<java-symbol type="bool" name="config_omnipresentCommunalUser"/>
<java-symbol type="bool" name="config_enableNewAutoSelectNetworkUI"/>
@@ -4364,10 +4366,6 @@
<java-symbol type="integer" name="config_unfoldTransitionHalfFoldedTimeout" />
<java-symbol type="array" name="config_perDeviceStateRotationLockDefaults" />
-
- <java-symbol type="array" name="config_disableApksUnlessMatchedSku_apk_list" />
- <java-symbol type="array" name="config_disableApkUnlessMatchedSku_skus_list" />
-
<java-symbol type="string" name="config_misprovisionedDeviceModel" />
<java-symbol type="string" name="config_misprovisionedBrandValue" />
@@ -5840,4 +5838,6 @@
<!-- Whether the device supports Wi-Fi USD feature. -->
<java-symbol type="bool" name="config_deviceSupportsWifiUsd" />
+ <java-symbol type="array" name="config_notificationDefaultUnsupportedAdjustments" />
+
</resources>
diff --git a/core/tests/coretests/src/android/app/NotificationManagerTest.java b/core/tests/coretests/src/android/app/NotificationManagerTest.java
index 3d6e1225bd92..18ba6a16bf72 100644
--- a/core/tests/coretests/src/android/app/NotificationManagerTest.java
+++ b/core/tests/coretests/src/android/app/NotificationManagerTest.java
@@ -19,6 +19,7 @@ package android.app;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
@@ -269,8 +270,9 @@ public class NotificationManagerTest {
// It doesn't matter what the returned contents are, as long as we return a channel.
// This setup must set up getNotificationChannels(), as that's the method called.
- when(mNotificationManager.mBackendService.getNotificationChannels(any(), any(),
- anyInt())).thenReturn(new ParceledListSlice<>(List.of(exampleChannel())));
+ when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), any(),
+ anyInt(), anyBoolean())).thenReturn(
+ new ParceledListSlice<>(List.of(exampleChannel())));
// ask for the same channel 100 times without invalidating the cache
for (int i = 0; i < 100; i++) {
@@ -282,7 +284,7 @@ public class NotificationManagerTest {
NotificationChannel unused = mNotificationManager.getNotificationChannel("id");
verify(mNotificationManager.mBackendService, times(2))
- .getNotificationChannels(any(), any(), anyInt());
+ .getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean());
}
@Test
@@ -295,23 +297,24 @@ public class NotificationManagerTest {
NotificationChannel c2 = new NotificationChannel("id2", "name2",
NotificationManager.IMPORTANCE_NONE);
- when(mNotificationManager.mBackendService.getNotificationChannels(any(), any(),
- anyInt())).thenReturn(new ParceledListSlice<>(List.of(c1, c2)));
+ when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), any(),
+ anyInt(), anyBoolean())).thenReturn(new ParceledListSlice<>(List.of(c1, c2)));
assertThat(mNotificationManager.getNotificationChannel("id1")).isEqualTo(c1);
assertThat(mNotificationManager.getNotificationChannel("id2")).isEqualTo(c2);
assertThat(mNotificationManager.getNotificationChannel("id3")).isNull();
verify(mNotificationManager.mBackendService, times(1))
- .getNotificationChannels(any(), any(), anyInt());
+ .getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean());
}
@Test
@EnableFlags(Flags.FLAG_NM_BINDER_PERF_CACHE_CHANNELS)
public void getNotificationChannels_cachedUntilInvalidated() throws Exception {
NotificationManager.invalidateNotificationChannelCache();
- when(mNotificationManager.mBackendService.getNotificationChannels(any(), any(),
- anyInt())).thenReturn(new ParceledListSlice<>(List.of(exampleChannel())));
+ when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), any(),
+ anyInt(), anyBoolean())).thenReturn(
+ new ParceledListSlice<>(List.of(exampleChannel())));
// ask for channels 100 times without invalidating the cache
for (int i = 0; i < 100; i++) {
@@ -323,7 +326,7 @@ public class NotificationManagerTest {
List<NotificationChannel> res = mNotificationManager.getNotificationChannels();
verify(mNotificationManager.mBackendService, times(2))
- .getNotificationChannels(any(), any(), anyInt());
+ .getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean());
assertThat(res).containsExactlyElementsIn(List.of(exampleChannel()));
}
@@ -341,8 +344,9 @@ public class NotificationManagerTest {
NotificationChannel c2 = new NotificationChannel("other", "name2",
NotificationManager.IMPORTANCE_DEFAULT);
- when(mNotificationManager.mBackendService.getNotificationChannels(any(), any(), anyInt()))
- .thenReturn(new ParceledListSlice<>(List.of(c1, conv1, c2)));
+ when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), any(),
+ anyInt(), anyBoolean())).thenReturn(
+ new ParceledListSlice<>(List.of(c1, conv1, c2)));
// Lookup for channel c1 and c2: returned as expected
assertThat(mNotificationManager.getNotificationChannel("id")).isEqualTo(c1);
@@ -359,9 +363,9 @@ public class NotificationManagerTest {
// Lookup of a nonexistent channel is null
assertThat(mNotificationManager.getNotificationChannel("id3")).isNull();
- // All of that should have been one call to getNotificationChannels()
+ // All of that should have been one call to getOrCreateNotificationChannels()
verify(mNotificationManager.mBackendService, times(1))
- .getNotificationChannels(any(), any(), anyInt());
+ .getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean());
}
@Test
@@ -381,12 +385,12 @@ public class NotificationManagerTest {
NotificationChannel channel3 = channel1.copy();
channel3.setName("name3");
- when(mNotificationManager.mBackendService.getNotificationChannels(any(), eq(pkg1),
- eq(userId))).thenReturn(new ParceledListSlice<>(List.of(channel1)));
- when(mNotificationManager.mBackendService.getNotificationChannels(any(), eq(pkg2),
- eq(userId))).thenReturn(new ParceledListSlice<>(List.of(channel2)));
- when(mNotificationManager.mBackendService.getNotificationChannels(any(), eq(pkg1),
- eq(userId1))).thenReturn(new ParceledListSlice<>(List.of(channel3)));
+ when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), eq(pkg1),
+ eq(userId), anyBoolean())).thenReturn(new ParceledListSlice<>(List.of(channel1)));
+ when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), eq(pkg2),
+ eq(userId), anyBoolean())).thenReturn(new ParceledListSlice<>(List.of(channel2)));
+ when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), eq(pkg1),
+ eq(userId1), anyBoolean())).thenReturn(new ParceledListSlice<>(List.of(channel3)));
// set our context to pretend to be from package 1 and userId 0
mContext.setParameters(pkg1, pkg1, userId);
@@ -402,7 +406,7 @@ public class NotificationManagerTest {
// Those should have been three different calls
verify(mNotificationManager.mBackendService, times(3))
- .getNotificationChannels(any(), any(), anyInt());
+ .getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean());
}
private Notification exampleNotification() {
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 7be6950fb613..ca6ad6fae46e 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -2504,21 +2504,6 @@ public class NotificationTest {
@Test
@EnableFlags(Flags.FLAG_API_RICH_ONGOING)
- public void progressStyle_setProgressSegments() {
- final List<Notification.ProgressStyle.Segment> segments = List.of(
- new Notification.ProgressStyle.Segment(100).setColor(Color.WHITE),
- new Notification.ProgressStyle.Segment(50).setColor(Color.RED),
- new Notification.ProgressStyle.Segment(50).setColor(Color.BLUE)
- );
-
- final Notification.ProgressStyle progressStyle1 = new Notification.ProgressStyle();
- progressStyle1.setProgressSegments(segments);
-
- assertThat(progressStyle1.getProgressSegments()).isEqualTo(segments);
- }
-
- @Test
- @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
public void progressStyle_addProgressPoint_dropsNegativePoints() {
// GIVEN
final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
@@ -2547,21 +2532,6 @@ public class NotificationTest {
@Test
@EnableFlags(Flags.FLAG_API_RICH_ONGOING)
- public void progressStyle_setProgressPoints() {
- final List<Notification.ProgressStyle.Point> points = List.of(
- new Notification.ProgressStyle.Point(0).setColor(Color.WHITE),
- new Notification.ProgressStyle.Point(50).setColor(Color.RED),
- new Notification.ProgressStyle.Point(100).setColor(Color.BLUE)
- );
-
- final Notification.ProgressStyle progressStyle1 = new Notification.ProgressStyle();
- progressStyle1.setProgressPoints(points);
-
- assertThat(progressStyle1.getProgressPoints()).isEqualTo(points);
- }
-
- @Test
- @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
public void progressStyle_createProgressModel_ignoresPointsExceedingMax() {
// GIVEN
final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
@@ -2703,58 +2673,11 @@ public class NotificationTest {
@Test
@EnableFlags(Flags.FLAG_API_RICH_ONGOING)
- public void progressStyle_setProgressIndeterminate() {
- final Notification.ProgressStyle progressStyle1 = new Notification.ProgressStyle();
- progressStyle1.setProgressIndeterminate(true);
- assertThat(progressStyle1.isProgressIndeterminate()).isTrue();
- }
-
- @Test
- @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
public void progressStyle_styledByProgress_defaultValueTrue() {
final Notification.ProgressStyle progressStyle1 = new Notification.ProgressStyle();
assertThat(progressStyle1.isStyledByProgress()).isTrue();
}
-
- @Test
- @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
- public void progressStyle_setStyledByProgress() {
- final Notification.ProgressStyle progressStyle1 = new Notification.ProgressStyle();
- progressStyle1.setStyledByProgress(false);
- assertThat(progressStyle1.isStyledByProgress()).isFalse();
- }
-
- @Test
- @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
- public void progressStyle_point() {
- final int id = 1;
- final int position = 10;
- final int color = Color.RED;
-
- final Notification.ProgressStyle.Point point =
- new Notification.ProgressStyle.Point(position).setId(id).setColor(color);
-
- assertEquals(id, point.getId());
- assertEquals(position, point.getPosition());
- assertEquals(color, point.getColor());
- }
-
- @Test
- @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
- public void progressStyle_segment() {
- final int id = 1;
- final int length = 100;
- final int color = Color.RED;
-
- final Notification.ProgressStyle.Segment segment =
- new Notification.ProgressStyle.Segment(length).setId(id).setColor(color);
-
- assertEquals(id, segment.getId());
- assertEquals(length, segment.getLength());
- assertEquals(color, segment.getColor());
- }
-
private void assertValid(Notification.Colors c) {
// Assert that all colors are populated
assertThat(c.getBackgroundColor()).isNotEqualTo(Notification.COLOR_INVALID);
diff --git a/core/tests/coretests/src/android/os/SystemHealthManagerUnitTest.java b/core/tests/coretests/src/android/os/SystemHealthManagerUnitTest.java
new file mode 100644
index 000000000000..1f9d4278b12e
--- /dev/null
+++ b/core/tests/coretests/src/android/os/SystemHealthManagerUnitTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.hardware.power.CpuHeadroomResult;
+import android.hardware.power.GpuHeadroomResult;
+import android.hardware.power.SupportInfo;
+import android.os.health.SystemHealthManager;
+import android.platform.test.annotations.DisabledOnRavenwood;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.internal.app.IBatteryStats;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@DisabledOnRavenwood(blockedBy = SystemHealthManager.class)
+public class SystemHealthManagerUnitTest {
+ @Mock
+ private IBatteryStats mBatteryStats;
+ @Mock
+ private IPowerStatsService mPowerStats;
+ @Mock
+ private IHintManager mHintManager;
+ private SystemHealthManager mSystemHealthManager;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ IHintManager.HintManagerClientData clientData = new IHintManager.HintManagerClientData();
+ clientData.supportInfo = new SupportInfo();
+ clientData.maxCpuHeadroomThreads = 10;
+ clientData.supportInfo.headroom = new SupportInfo.HeadroomSupportInfo();
+ clientData.supportInfo.headroom.isCpuSupported = true;
+ clientData.supportInfo.headroom.isGpuSupported = true;
+ clientData.supportInfo.headroom.cpuMinCalculationWindowMillis = 45;
+ clientData.supportInfo.headroom.cpuMaxCalculationWindowMillis = 9999;
+ clientData.supportInfo.headroom.gpuMinCalculationWindowMillis = 46;
+ clientData.supportInfo.headroom.gpuMaxCalculationWindowMillis = 9998;
+ clientData.supportInfo.headroom.cpuMinIntervalMillis = 999;
+ clientData.supportInfo.headroom.gpuMinIntervalMillis = 998;
+ when(mHintManager.getClientData()).thenReturn(clientData);
+ mSystemHealthManager = new SystemHealthManager(mBatteryStats, mPowerStats, mHintManager);
+ }
+
+ @Test
+ public void testHeadroomParamsValueRange() {
+ assertEquals(999, mSystemHealthManager.getCpuHeadroomMinIntervalMillis());
+ assertEquals(998, mSystemHealthManager.getGpuHeadroomMinIntervalMillis());
+ assertEquals(45, (int) mSystemHealthManager.getCpuHeadroomCalculationWindowRange().first);
+ assertEquals(9999,
+ (int) mSystemHealthManager.getCpuHeadroomCalculationWindowRange().second);
+ assertEquals(46, (int) mSystemHealthManager.getGpuHeadroomCalculationWindowRange().first);
+ assertEquals(9998,
+ (int) mSystemHealthManager.getGpuHeadroomCalculationWindowRange().second);
+ assertEquals(10, (int) mSystemHealthManager.getMaxCpuHeadroomTidsSize());
+ }
+
+ @Test
+ public void testGetCpuHeadroom() throws RemoteException, InterruptedException {
+ final CpuHeadroomParams params1 = null;
+ final CpuHeadroomParamsInternal internalParams1 = new CpuHeadroomParamsInternal();
+
+ final CpuHeadroomParams params2 = new CpuHeadroomParams.Builder()
+ .setCalculationWindowMillis(100)
+ .build();
+ final CpuHeadroomParamsInternal internalParams2 = new CpuHeadroomParamsInternal();
+ internalParams2.calculationWindowMillis = 100;
+
+ final CpuHeadroomParams params3 = new CpuHeadroomParams.Builder()
+ .setCalculationType(CpuHeadroomParams.CPU_HEADROOM_CALCULATION_TYPE_AVERAGE)
+ .build();
+ final CpuHeadroomParamsInternal internalParams3 = new CpuHeadroomParamsInternal();
+ internalParams3.calculationType =
+ (byte) CpuHeadroomParams.CPU_HEADROOM_CALCULATION_TYPE_AVERAGE;
+
+ final CpuHeadroomParams params4 = new CpuHeadroomParams.Builder()
+ .setTids(1000, 1001)
+ .build();
+ final CpuHeadroomParamsInternal internalParams4 = new CpuHeadroomParamsInternal();
+ internalParams4.tids = new int[]{1000, 1001};
+
+ when(mHintManager.getCpuHeadroom(internalParams1)).thenReturn(
+ CpuHeadroomResult.globalHeadroom(99f));
+ when(mHintManager.getCpuHeadroom(internalParams2)).thenReturn(
+ CpuHeadroomResult.globalHeadroom(98f));
+ when(mHintManager.getCpuHeadroom(internalParams3)).thenReturn(
+ CpuHeadroomResult.globalHeadroom(97f));
+ when(mHintManager.getCpuHeadroom(internalParams4)).thenReturn(null);
+
+ assertEquals(99f, mSystemHealthManager.getCpuHeadroom(params1), 0.001f);
+ assertEquals(98f, mSystemHealthManager.getCpuHeadroom(params2), 0.001f);
+ assertEquals(97f, mSystemHealthManager.getCpuHeadroom(params3), 0.001f);
+ assertTrue(Float.isNaN(mSystemHealthManager.getCpuHeadroom(params4)));
+ verify(mHintManager, times(1)).getCpuHeadroom(internalParams1);
+ verify(mHintManager, times(1)).getCpuHeadroom(internalParams2);
+ verify(mHintManager, times(1)).getCpuHeadroom(internalParams3);
+ verify(mHintManager, times(1)).getCpuHeadroom(internalParams4);
+ }
+
+ @Test
+ public void testGetGpuHeadroom() throws RemoteException, InterruptedException {
+ final GpuHeadroomParams params1 = null;
+ final GpuHeadroomParamsInternal internalParams1 = new GpuHeadroomParamsInternal();
+ final GpuHeadroomParams params2 = new GpuHeadroomParams.Builder()
+ .setCalculationWindowMillis(100)
+ .build();
+ final GpuHeadroomParamsInternal internalParams2 = new GpuHeadroomParamsInternal();
+ internalParams2.calculationWindowMillis = 100;
+ final GpuHeadroomParams params3 = new GpuHeadroomParams.Builder()
+ .setCalculationType(GpuHeadroomParams.GPU_HEADROOM_CALCULATION_TYPE_AVERAGE)
+ .build();
+ final GpuHeadroomParamsInternal internalParams3 = new GpuHeadroomParamsInternal();
+ internalParams3.calculationType =
+ (byte) GpuHeadroomParams.GPU_HEADROOM_CALCULATION_TYPE_AVERAGE;
+
+ when(mHintManager.getGpuHeadroom(internalParams1)).thenReturn(
+ GpuHeadroomResult.globalHeadroom(99f));
+ when(mHintManager.getGpuHeadroom(internalParams2)).thenReturn(
+ GpuHeadroomResult.globalHeadroom(98f));
+ when(mHintManager.getGpuHeadroom(internalParams3)).thenReturn(null);
+
+ assertEquals(99f, mSystemHealthManager.getGpuHeadroom(params1), 0.001f);
+ assertEquals(98f, mSystemHealthManager.getGpuHeadroom(params2), 0.001f);
+ assertTrue(Float.isNaN(mSystemHealthManager.getGpuHeadroom(params3)));
+ verify(mHintManager, times(1)).getGpuHeadroom(internalParams1);
+ verify(mHintManager, times(1)).getGpuHeadroom(internalParams2);
+ verify(mHintManager, times(1)).getGpuHeadroom(internalParams3);
+ }
+}
diff --git a/core/tests/coretests/src/android/provider/SettingsProviderTest.java b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
index 133177935984..c58d53ba967c 100644
--- a/core/tests/coretests/src/android/provider/SettingsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
@@ -20,6 +20,7 @@ import static org.hamcrest.Matchers.aMapWithSize;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.junit.Assert.assertThat;
+import android.app.UiAutomation;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -38,6 +39,7 @@ import android.test.AndroidTestCase;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
import androidx.test.filters.Suppress;
+import androidx.test.platform.app.InstrumentationRegistry;
import java.util.HashMap;
import java.util.List;
@@ -447,4 +449,50 @@ public class SettingsProviderTest extends AndroidTestCase {
r.call(Settings.Config.CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, newName, null);
}
}
+
+ @SmallTest
+ public void testCall_putOverrideConfig() throws Exception {
+ // The shell user is restricted to a set of allowlisted flags / namespaces that can be
+ // written. When an flag override is requested, the flag is rewritten to be in the form:
+ // device_config_overrides/namespace:flagname
+ // To avoid requiring allowlisting both the base flag and the override version,
+ // SettingsProvider will parse out the overridden flag and check if it has been allowlisted.
+ // This test verifies that this is properly handled for both the good case as well as when
+ // the overridden flag is not in the proper format by ensuring a SecurityException is not
+ // thrown since these flags have been allowlisted.
+ UiAutomation uiAutomation =
+ InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ uiAutomation.adoptShellPermissionIdentity();
+ ContentResolver r = getContext().getContentResolver();
+ String overridesNamespace = "device_config_overrides";
+ String namespace = "namespace1";
+ String flagName = "key1";
+ String validFlag = overridesNamespace + "/" + namespace + ":" + flagName;
+ String invalidFlag1 = overridesNamespace + "/";
+ String invalidFlag2 = overridesNamespace + "/" + namespace + ":";
+ String invalidFlag3 = overridesNamespace + "/" + ":";
+ String value = "value1";
+ Bundle args = new Bundle();
+ args.putString(Settings.NameValueTable.VALUE, value);
+
+ try {
+ r.call(Settings.Config.CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, validFlag, args);
+ r.call(Settings.Config.CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, invalidFlag1,
+ args);
+ r.call(Settings.Config.CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, invalidFlag2,
+ args);
+ r.call(Settings.Config.CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, invalidFlag3,
+ args);
+ } finally {
+ r.call(Settings.Config.CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, validFlag,
+ null);
+ r.call(Settings.Config.CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, invalidFlag1,
+ null);
+ r.call(Settings.Config.CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, invalidFlag2,
+ null);
+ r.call(Settings.Config.CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, invalidFlag3,
+ null);
+ uiAutomation.dropShellPermissionIdentity();
+ }
+ }
}
diff --git a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
index 504240812559..7a4cc7f98a1a 100644
--- a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
+++ b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
@@ -22,6 +22,7 @@ import static junit.framework.Assert.assertNotSame;
import static junit.framework.Assert.assertNull;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
@@ -35,14 +36,19 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.metrics.LogMaker;
import android.os.UserHandle;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.view.Display;
import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.window.flags.Flags;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -52,11 +58,16 @@ import org.mockito.MockitoAnnotations;
@SmallTest
public class StatusBarNotificationTest {
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private final Context mMockContext = mock(Context.class);
@Mock
private Context mRealContext;
@Mock
private PackageManager mPm;
+ @Mock
+ private Context mSecondaryDisplayContext;
private static final String PKG = "com.example.o";
private static final int UID = 9583;
@@ -80,6 +91,10 @@ public class StatusBarNotificationTest {
InstrumentationRegistry.getContext().getResources());
when(mMockContext.getPackageManager()).thenReturn(mPm);
when(mMockContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
+ when(mMockContext.getDisplayId()).thenReturn(Display.DEFAULT_DISPLAY);
+ when(mSecondaryDisplayContext.getPackageManager()).thenReturn(mPm);
+ when(mSecondaryDisplayContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
+ when(mSecondaryDisplayContext.getDisplayId()).thenReturn(2);
when(mPm.getApplicationLabel(any())).thenReturn("");
mRealContext = InstrumentationRegistry.getContext();
@@ -221,6 +236,24 @@ public class StatusBarNotificationTest {
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_PER_DISPLAY_PACKAGE_CONTEXT_CACHE_IN_STATUSBAR_NOTIF)
+ public void testGetPackageContext_multipleDisplaysCase() {
+ String pkg = "com.android.systemui";
+ int uid = 1000;
+ Notification notification = getNotificationBuilder(GROUP_ID_1, CHANNEL_ID).build();
+ StatusBarNotification sbn = new StatusBarNotification(
+ pkg, pkg, ID, TAG, uid, uid, notification, UserHandle.ALL, null, UID);
+ Context defaultContext = sbn.getPackageContext(mRealContext);
+ Context secondaryContext = sbn.getPackageContext(mSecondaryDisplayContext);
+ assertNotSame(mRealContext, defaultContext);
+ assertNotSame(defaultContext, secondaryContext);
+
+ // Let's make sure it caches it:
+ assertSame(defaultContext, sbn.getPackageContext(mRealContext));
+ assertSame(secondaryContext, sbn.getPackageContext(mSecondaryDisplayContext));
+ }
+
+ @Test
public void testGetUidFromKey() {
StatusBarNotification sbn = getNotification("pkg", null, "channel");
diff --git a/core/tests/coretests/src/android/text/LayoutTest.java b/core/tests/coretests/src/android/text/LayoutTest.java
index c7d85d4b9b76..9e78af57b470 100644
--- a/core/tests/coretests/src/android/text/LayoutTest.java
+++ b/core/tests/coretests/src/android/text/LayoutTest.java
@@ -1024,6 +1024,55 @@ public class LayoutTest {
expect.that(backgroundCommands.size()).isEqualTo(backgroundRectsDrawn);
}
+ @Test
+ @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT)
+ public void highContrastTextEnabled_testWhitespaceText_DrawsBackgroundsWithAdjacentLetters() {
+ mTextPaint.setColor(Color.BLACK);
+ SpannableString spannedText = new SpannableString("Test\tTap and Space");
+
+ // Set the entire text to white initially
+ spannedText.setSpan(
+ new ForegroundColorSpan(Color.WHITE),
+ /* start= */ 0,
+ /* end= */ spannedText.length(),
+ Spanned.SPAN_INCLUSIVE_EXCLUSIVE
+ );
+
+ // Find the whitespace character and set its color to black
+ for (int i = 0; i < spannedText.length(); i++) {
+ if (Character.isWhitespace(spannedText.charAt(i))) {
+ spannedText.setSpan(
+ new ForegroundColorSpan(Color.BLACK),
+ i,
+ i + 1,
+ Spanned.SPAN_INCLUSIVE_EXCLUSIVE
+ );
+ }
+ }
+
+ Layout layout = new StaticLayout(spannedText, mTextPaint, mWidth,
+ mAlign, mSpacingMult, mSpacingAdd, /* includePad= */ false);
+
+ MockCanvas c = new MockCanvas(/* width= */ 256, /* height= */ 256);
+ c.setHighContrastTextEnabled(true);
+ layout.draw(
+ c,
+ /* highlightPaths= */ null,
+ /* highlightPaints= */ null,
+ /* selectionPath= */ null,
+ /* selectionPaint= */ null,
+ /* cursorOffsetVertical= */ 0
+ );
+
+ List<MockCanvas.DrawCommand> drawCommands = c.getDrawCommands();
+ for (int i = 0; i < drawCommands.size(); i++) {
+ MockCanvas.DrawCommand drawCommand = drawCommands.get(i);
+ if (drawCommand.rect != null) {
+ expect.that(removeAlpha(drawCommand.paint.getColor())).isEqualTo(Color.BLACK);
+ }
+ }
+ }
+
private int removeAlpha(int color) {
return Color.rgb(
Color.red(color),
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java b/core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java
index 1a9af6b55eed..d1555e389c2d 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java
@@ -20,8 +20,8 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATI
import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_MAGNIFICATION_CONTROLLER;
import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR;
-import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
-import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.KEY_GESTURE;
+import static com.android.internal.accessibility.common.ShortcutConstants.USER_SHORTCUT_TYPES;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.DEFAULT;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
import static com.google.common.truth.Truth.assertThat;
@@ -42,19 +42,22 @@ import android.testing.TestableContext;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.internal.accessibility.AccessibilityShortcutController;
import com.android.internal.accessibility.TestUtils;
import com.android.internal.accessibility.common.ShortcutConstants;
+import com.google.testing.junit.testparameterinjector.TestParameter;
+import com.google.testing.junit.testparameterinjector.TestParameterInjector;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.StringJoiner;
@@ -62,7 +65,7 @@ import java.util.StringJoiner;
/**
* Unit Tests for {@link com.android.internal.accessibility.util.ShortcutUtils}
*/
-@RunWith(AndroidJUnit4.class)
+@RunWith(TestParameterInjector.class)
public class ShortcutUtilsTest {
private static final Set<String> ONE_COMPONENT = Set.of(
new ComponentName("pkg", "serv").flattenToString());
@@ -99,38 +102,19 @@ public class ShortcutUtilsTest {
}
@Test
- public void getShortcutTargets_softwareShortcutNoService_emptyResult() {
- assertThat(
- ShortcutUtils.getShortcutTargetsFromSettings(
- mContext, SOFTWARE, mDefaultUserId)
- ).isEmpty();
- }
-
- @Test
- public void getShortcutTargets_volumeKeyShortcutNoService_emptyResult() {
- assertThat(
- ShortcutUtils.getShortcutTargetsFromSettings(
- mContext, ShortcutConstants.UserShortcutType.HARDWARE,
- mDefaultUserId)
- ).isEmpty();
- }
-
- @Test
- public void getShortcutTargets_gestureShortcutNoService_emptyResult() {
- assertThat(
- ShortcutUtils.getShortcutTargetsFromSettings(
- mContext, GESTURE, mDefaultUserId)
- ).isEmpty();
- }
+ public void getShortcutTargets_noService_emptyResult(
+ @TestParameter(valuesProvider = ShortcutTypeValueProvider.class) int shortcutType) {
+ Settings.Secure.putStringForUser(
+ mContext.getContentResolver(),
+ ShortcutUtils.convertToKey(shortcutType), "", mContext.getUserId());
- @Test
- public void getShortcutTargets_keyGestureShortcutNoService_emptyResult() {
assertThat(
ShortcutUtils.getShortcutTargetsFromSettings(
- mContext, KEY_GESTURE, mDefaultUserId)
+ mContext, shortcutType, mDefaultUserId)
).isEmpty();
}
+ // TODO 385186274: Parameterize this test.
@Test
public void getShortcutTargets_softwareShortcut1Service_return1Service() {
setupShortcutTargets(ONE_COMPONENT, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
@@ -143,6 +127,7 @@ public class ShortcutUtilsTest {
).containsExactlyElementsIn(ONE_COMPONENT);
}
+ // TODO 385186274: Parameterize this test.
@Test
public void getShortcutTargets_volumeShortcut2Service_return2Service() {
setupShortcutTargets(ONE_COMPONENT, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
@@ -155,6 +140,7 @@ public class ShortcutUtilsTest {
).containsExactlyElementsIn(TWO_COMPONENTS);
}
+ // TODO 385186274: Parameterize this test.
@Test
public void getShortcutTargets_tripleTapShortcut_magnificationDisabled_emptyResult() {
enableTripleTapShortcutForMagnification(/* enable= */ false);
@@ -168,6 +154,7 @@ public class ShortcutUtilsTest {
).isEmpty();
}
+ // TODO 385186274: Parameterize this test.
@Test
public void getShortcutTargets_tripleTapShortcut_magnificationEnabled_returnMagnification() {
setupShortcutTargets(ONE_COMPONENT, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
@@ -181,6 +168,7 @@ public class ShortcutUtilsTest {
).containsExactly(ACCESSIBILITY_SHORTCUT_TARGET_MAGNIFICATION_CONTROLLER);
}
+ // TODO 385186274: Parameterize this test.
@Test
public void updateAccessibilityServiceStateIfNeeded_alwaysOnServiceOn_noShortcuts_serviceTurnedOff() {
setupA11yServiceAndShortcutState(
@@ -195,6 +183,7 @@ public class ShortcutUtilsTest {
assertA11yServiceState(ALWAYS_ON_SERVICE_COMPONENT_NAME, /* enabled= */ false);
}
+ // TODO 385186274: Parameterize this test.
@Test
public void updateAccessibilityServiceStateIfNeeded_alwaysOnServiceOnForBothUsers_noShortcutsForGuestUser_serviceTurnedOffForGuestUserOnly() {
// setup arbitrary userId by add 10 to the default user id
@@ -218,6 +207,7 @@ public class ShortcutUtilsTest {
ALWAYS_ON_SERVICE_COMPONENT_NAME, /* enabled= */ true, mDefaultUserId);
}
+ // TODO 385186274: Parameterize this test.
@Test
public void updateAccessibilityServiceStateIfNeeded_alwaysOnServiceOn_hasShortcut_serviceKeepsOn() {
setupA11yServiceAndShortcutState(
@@ -232,6 +222,7 @@ public class ShortcutUtilsTest {
assertA11yServiceState(ALWAYS_ON_SERVICE_COMPONENT_NAME, /* enabled= */ true);
}
+ // TODO 385186274: Parameterize this test.
@Test
public void updateAccessibilityServiceStateIfNeeded_alwaysOnServiceOff_noShortcuts_serviceKeepsOff() {
setupA11yServiceAndShortcutState(
@@ -246,6 +237,7 @@ public class ShortcutUtilsTest {
assertA11yServiceState(ALWAYS_ON_SERVICE_COMPONENT_NAME, /* enabled= */ false);
}
+ // TODO 385186274: Parameterize this test.
@Test
public void updateAccessibilityServiceStateIfNeeded_alwaysOnServiceOff_hasShortcuts_serviceTurnsOn() {
setupA11yServiceAndShortcutState(
@@ -260,6 +252,7 @@ public class ShortcutUtilsTest {
assertA11yServiceState(ALWAYS_ON_SERVICE_COMPONENT_NAME, /* enabled= */ true);
}
+ // TODO 385186274: Parameterize this test.
@Test
public void updateAccessibilityServiceStateIfNeeded_standardA11yServiceOn_noShortcuts_serviceKeepsOn() {
setupA11yServiceAndShortcutState(
@@ -274,6 +267,7 @@ public class ShortcutUtilsTest {
assertA11yServiceState(STANDARD_SERVICE_COMPONENT_NAME, /* enabled= */ true);
}
+ // TODO 385186274: Parameterize this test.
@Test
public void updateAccessibilityServiceStateIfNeeded_standardA11yServiceOn_hasShortcuts_serviceKeepsOn() {
setupA11yServiceAndShortcutState(
@@ -288,6 +282,7 @@ public class ShortcutUtilsTest {
assertA11yServiceState(STANDARD_SERVICE_COMPONENT_NAME, /* enabled= */ true);
}
+ // TODO 385186274: Parameterize this test.
@Test
public void updateAccessibilityServiceStateIfNeeded_standardA11yServiceOff_noShortcuts_serviceKeepsOff() {
setupA11yServiceAndShortcutState(
@@ -302,6 +297,7 @@ public class ShortcutUtilsTest {
assertA11yServiceState(STANDARD_SERVICE_COMPONENT_NAME, /* enabled= */ false);
}
+ // TODO 385186274: Parameterize this test.
@Test
public void updateAccessibilityServiceStateIfNeeded_standardA11yServiceOff_hasShortcuts_serviceKeepsOff() {
setupA11yServiceAndShortcutState(
@@ -316,6 +312,37 @@ public class ShortcutUtilsTest {
assertA11yServiceState(STANDARD_SERVICE_COMPONENT_NAME, /* enabled= */ false);
}
+ @Test
+ public void getEnabledShortcutTypes_oneShortcut_returnsExpectedType(
+ @TestParameter(valuesProvider = ShortcutTypeValueProvider.class) int shortcutType)
+ throws RemoteException {
+ clearMockShortcutTypes();
+ assertThat(ShortcutUtils.getEnabledShortcutTypes(
+ mContext, STANDARD_SERVICE_COMPONENT_NAME)).isEqualTo(DEFAULT);
+ mockShortcutType(shortcutType, STANDARD_SERVICE_COMPONENT_NAME);
+ assertThat(ShortcutUtils.getEnabledShortcutTypes(
+ mContext, STANDARD_SERVICE_COMPONENT_NAME)).isEqualTo(shortcutType);
+
+ }
+
+ @Test
+ public void getEnabledShortcutTypes_twoShortcuts_returnsExpectedTypes(
+ @TestParameter(valuesProvider = ShortcutTypeValueProvider.class) int shortcutType1,
+ @TestParameter(valuesProvider = ShortcutTypeValueProvider.class) int shortcutType2
+ ) throws RemoteException {
+ if (shortcutType1 == shortcutType2) {
+ return;
+ }
+ clearMockShortcutTypes();
+ assertThat(ShortcutUtils.getEnabledShortcutTypes(
+ mContext, STANDARD_SERVICE_COMPONENT_NAME)).isEqualTo(DEFAULT);
+ mockShortcutType(shortcutType1, STANDARD_SERVICE_COMPONENT_NAME);
+ mockShortcutType(shortcutType2, STANDARD_SERVICE_COMPONENT_NAME);
+ assertThat(ShortcutUtils.getEnabledShortcutTypes(
+ mContext, STANDARD_SERVICE_COMPONENT_NAME)).isEqualTo(
+ shortcutType1 | shortcutType2);
+ }
+
private void setupShortcutTargets(Set<String> components, String shortcutSettingsKey) {
final StringJoiner stringJoiner = new StringJoiner(String.valueOf(SERVICES_SEPARATOR));
for (String target : components) {
@@ -403,4 +430,29 @@ public class ShortcutUtilsTest {
add ? a11yServiceComponentName : "",
userId);
}
+
+ private void clearMockShortcutTypes() throws RemoteException {
+ for (int shortcutType : ShortcutConstants.USER_SHORTCUT_TYPES) {
+ when(mAccessibilityManagerService
+ .getAccessibilityShortcutTargets(shortcutType)).thenReturn(List.of());
+ }
+ }
+
+ private void mockShortcutType(int shortcutType, String componentName)
+ throws RemoteException {
+ when(mAccessibilityManagerService.getAccessibilityShortcutTargets(shortcutType))
+ .thenReturn(List.of(componentName));
+ }
+
+ static final class ShortcutTypeValueProvider implements
+ TestParameter.TestParameterValuesProvider {
+ @Override
+ public List<Integer> provideValues() {
+ List<Integer> values = new ArrayList<>();
+ for (int shortcutType: USER_SHORTCUT_TYPES) {
+ values.add(shortcutType);
+ }
+ return values;
+ }
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/widget/NotificationProgressBarTest.java b/core/tests/coretests/src/com/android/internal/widget/NotificationProgressBarTest.java
index 5df2c1279eb8..9818e19cea02 100644
--- a/core/tests/coretests/src/com/android/internal/widget/NotificationProgressBarTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/NotificationProgressBarTest.java
@@ -336,10 +336,14 @@ public class NotificationProgressBarTest {
progress, progressMax);
List<Part> expectedParts = new ArrayList<>(
- List.of(new Segment(0.15f, Color.BLUE), new Point(Color.RED),
- new Segment(0.10f, Color.BLUE), new Point(Color.BLUE),
- new Segment(0.35f, Color.BLUE), new Point(Color.BLUE),
- new Segment(0.15f, Color.BLUE), new Point(Color.YELLOW),
+ List.of(new Segment(0.15f, Color.BLUE),
+ new Point(Color.RED),
+ new Segment(0.10f, Color.BLUE),
+ new Point(Color.BLUE),
+ new Segment(0.35f, Color.BLUE),
+ new Point(Color.BLUE),
+ new Segment(0.15f, Color.BLUE),
+ new Point(Color.YELLOW),
new Segment(0.25f, Color.BLUE)));
assertThat(parts).isEqualTo(expectedParts);
@@ -408,11 +412,16 @@ public class NotificationProgressBarTest {
progress, progressMax);
List<Part> expectedParts = new ArrayList<>(
- List.of(new Segment(0.15f, Color.RED), new Point(Color.RED),
- new Segment(0.10f, Color.RED), new Point(Color.BLUE),
- new Segment(0.25f, Color.RED), new Segment(0.10f, Color.GREEN),
- new Point(Color.BLUE), new Segment(0.15f, Color.GREEN),
- new Point(Color.YELLOW), new Segment(0.25f, Color.GREEN)));
+ List.of(new Segment(0.15f, Color.RED),
+ new Point(Color.RED),
+ new Segment(0.10f, Color.RED),
+ new Point(Color.BLUE),
+ new Segment(0.25f, Color.RED),
+ new Segment(0.10f, Color.GREEN),
+ new Point(Color.BLUE),
+ new Segment(0.15f, Color.GREEN),
+ new Point(Color.YELLOW),
+ new Segment(0.25f, Color.GREEN)));
assertThat(parts).isEqualTo(expectedParts);
@@ -464,6 +473,158 @@ public class NotificationProgressBarTest {
}
@Test
+ public void processAndConvertToParts_multipleSegmentsWithPointsAtStartAndEnd() {
+ List<ProgressStyle.Segment> segments = new ArrayList<>();
+ segments.add(new ProgressStyle.Segment(50).setColor(Color.RED));
+ segments.add(new ProgressStyle.Segment(50).setColor(Color.GREEN));
+ List<ProgressStyle.Point> points = new ArrayList<>();
+ points.add(new ProgressStyle.Point(0).setColor(Color.RED));
+ points.add(new ProgressStyle.Point(25).setColor(Color.BLUE));
+ points.add(new ProgressStyle.Point(60).setColor(Color.BLUE));
+ points.add(new ProgressStyle.Point(100).setColor(Color.YELLOW));
+ int progress = 60;
+ int progressMax = 100;
+
+ List<Part> parts = NotificationProgressBar.processAndConvertToViewParts(segments, points,
+ progress, progressMax);
+
+ List<Part> expectedParts = new ArrayList<>(
+ List.of(new Point(Color.RED),
+ new Segment(0.25f, Color.RED),
+ new Point(Color.BLUE),
+ new Segment(0.25f, Color.RED),
+ new Segment(0.10f, Color.GREEN),
+ new Point(Color.BLUE),
+ new Segment(0.4f, Color.GREEN),
+ new Point(Color.YELLOW)));
+
+ assertThat(parts).isEqualTo(expectedParts);
+
+ float drawableWidth = 300;
+ float segSegGap = 4;
+ float segPointGap = 4;
+ float pointRadius = 6;
+ boolean hasTrackerIcon = true;
+ List<DrawablePart> drawableParts = NotificationProgressBar.processAndConvertToDrawableParts(
+ parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon);
+
+ List<DrawablePart> expectedDrawableParts = new ArrayList<>(
+ List.of(new DrawablePoint(0, 12, Color.RED),
+ new DrawableSegment(16, 65, Color.RED),
+ new DrawablePoint(69, 81, Color.BLUE),
+ new DrawableSegment(85, 146, Color.RED),
+ new DrawableSegment(150, 170, Color.GREEN),
+ new DrawablePoint(174, 186, Color.BLUE),
+ new DrawableSegment(190, 284, Color.GREEN),
+ new DrawablePoint(288, 300, Color.YELLOW)));
+
+ assertThat(drawableParts).isEqualTo(expectedDrawableParts);
+
+ float segmentMinWidth = 16;
+ boolean isStyledByProgress = true;
+
+ Pair<List<DrawablePart>, Float> p = NotificationProgressBar.maybeStretchAndRescaleSegments(
+ parts, drawableParts, segmentMinWidth, pointRadius, (float) progress / progressMax,
+ 300, isStyledByProgress, hasTrackerIcon ? 0 : segSegGap);
+
+ // Colors with 40% opacity
+ int fadedGreen = 0x6600FF00;
+ int fadedYellow = 0x66FFFF00;
+ expectedDrawableParts = new ArrayList<>(
+ List.of(new DrawablePoint(0, 12, Color.RED),
+ new DrawableSegment(16, 65, Color.RED),
+ new DrawablePoint(69, 81, Color.BLUE),
+ new DrawableSegment(85, 146, Color.RED),
+ new DrawableSegment(150, 170, Color.GREEN),
+ new DrawablePoint(174, 186, Color.BLUE),
+ new DrawableSegment(190, 284, fadedGreen, true),
+ new DrawablePoint(288, 300, fadedYellow)));
+
+ assertThat(p.second).isEqualTo(180);
+ assertThat(p.first).isEqualTo(expectedDrawableParts);
+ }
+
+ // The points are so close to start/end that they would go out of bounds without the minimum
+ // segment width requirement.
+ @Test
+ public void processAndConvertToParts_multipleSegmentsWithPointsNearStartAndEnd() {
+ List<ProgressStyle.Segment> segments = new ArrayList<>();
+ segments.add(new ProgressStyle.Segment(50).setColor(Color.RED));
+ segments.add(new ProgressStyle.Segment(50).setColor(Color.GREEN));
+ List<ProgressStyle.Point> points = new ArrayList<>();
+ points.add(new ProgressStyle.Point(1).setColor(Color.RED));
+ points.add(new ProgressStyle.Point(25).setColor(Color.BLUE));
+ points.add(new ProgressStyle.Point(60).setColor(Color.BLUE));
+ points.add(new ProgressStyle.Point(99).setColor(Color.YELLOW));
+ int progress = 60;
+ int progressMax = 100;
+
+ List<Part> parts = NotificationProgressBar.processAndConvertToViewParts(segments, points,
+ progress, progressMax);
+
+ List<Part> expectedParts = new ArrayList<>(
+ List.of(new Segment(0.01f, Color.RED),
+ new Point(Color.RED),
+ new Segment(0.24f, Color.RED),
+ new Point(Color.BLUE),
+ new Segment(0.25f, Color.RED),
+ new Segment(0.10f, Color.GREEN),
+ new Point(Color.BLUE),
+ new Segment(0.39f, Color.GREEN),
+ new Point(Color.YELLOW),
+ new Segment(0.01f, Color.GREEN)));
+
+ assertThat(parts).isEqualTo(expectedParts);
+
+ float drawableWidth = 300;
+ float segSegGap = 4;
+ float segPointGap = 4;
+ float pointRadius = 6;
+ boolean hasTrackerIcon = true;
+ List<DrawablePart> drawableParts = NotificationProgressBar.processAndConvertToDrawableParts(
+ parts, drawableWidth, segSegGap, segPointGap, pointRadius, hasTrackerIcon);
+
+ List<DrawablePart> expectedDrawableParts = new ArrayList<>(
+ List.of(new DrawableSegment(0, -7, Color.RED),
+ new DrawablePoint(-3, 9, Color.RED),
+ new DrawableSegment(13, 65, Color.RED),
+ new DrawablePoint(69, 81, Color.BLUE),
+ new DrawableSegment(85, 146, Color.RED),
+ new DrawableSegment(150, 170, Color.GREEN),
+ new DrawablePoint(174, 186, Color.BLUE),
+ new DrawableSegment(190, 287, Color.GREEN),
+ new DrawablePoint(291, 303, Color.YELLOW),
+ new DrawableSegment(307, 300, Color.GREEN)));
+
+ assertThat(drawableParts).isEqualTo(expectedDrawableParts);
+
+ float segmentMinWidth = 16;
+ boolean isStyledByProgress = true;
+
+ Pair<List<DrawablePart>, Float> p = NotificationProgressBar.maybeStretchAndRescaleSegments(
+ parts, drawableParts, segmentMinWidth, pointRadius, (float) progress / progressMax,
+ 300, isStyledByProgress, hasTrackerIcon ? 0 : segSegGap);
+
+ // Colors with 40% opacity
+ int fadedGreen = 0x6600FF00;
+ int fadedYellow = 0x66FFFF00;
+ expectedDrawableParts = new ArrayList<>(
+ List.of(new DrawableSegment(0, 16, Color.RED),
+ new DrawablePoint(20, 32, Color.RED),
+ new DrawableSegment(36, 78.02409F, Color.RED),
+ new DrawablePoint(82.02409F, 94.02409F, Color.BLUE),
+ new DrawableSegment(98.02409F, 146.55421F, Color.RED),
+ new DrawableSegment(150.55421F, 169.44579F, Color.GREEN),
+ new DrawablePoint(173.44579F, 185.44579F, Color.BLUE),
+ new DrawableSegment(189.44579F, 264, fadedGreen, true),
+ new DrawablePoint(268, 280, fadedYellow),
+ new DrawableSegment(284, 300, fadedGreen, true)));
+
+ assertThat(p.second).isEqualTo(179.44579F);
+ assertThat(p.first).isEqualTo(expectedDrawableParts);
+ }
+
+ @Test
public void processAndConvertToParts_multipleSegmentsWithPoints_notStyledByProgress() {
List<ProgressStyle.Segment> segments = new ArrayList<>();
segments.add(new ProgressStyle.Segment(50).setColor(Color.RED));
diff --git a/data/etc/preinstalled-packages-platform.xml b/data/etc/preinstalled-packages-platform.xml
index 782327713fdc..3b4014867ef7 100644
--- a/data/etc/preinstalled-packages-platform.xml
+++ b/data/etc/preinstalled-packages-platform.xml
@@ -102,7 +102,7 @@ Changes to the whitelist during system updates can result in installing addition
to pre-existing users, but cannot uninstall pre-existing system packages from pre-existing users.
-->
<config>
- <!-- Bluetooth (com.android.btservices apex) - visible on the sharesheet -->
+ <!-- Bluetooth (com.android.bt apex) - visible on the sharesheet -->
<install-in-user-type package="com.android.bluetooth">
<install-in user-type="SYSTEM" />
<install-in user-type="FULL" />
@@ -134,4 +134,9 @@ to pre-existing users, but cannot uninstall pre-existing system packages from pr
<install-in-user-type package="com.android.avatarpicker">
<install-in user-type="FULL" />
</install-in-user-type>
+
+ <!-- Users Widget (Users widget)-->
+ <install-in-user-type package="com.android.multiuser">
+ <install-in user-type="FULL" />
+ </install-in-user-type>
</config>
diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java
index 906c71d9caca..1c34e0d54908 100644
--- a/graphics/java/android/graphics/BLASTBufferQueue.java
+++ b/graphics/java/android/graphics/BLASTBufferQueue.java
@@ -66,12 +66,6 @@ public final class BLASTBufferQueue {
}
/** Create a new connection with the surface flinger. */
- public BLASTBufferQueue(String name, SurfaceControl sc, int width, int height,
- @PixelFormat.Format int format) {
- this(name, true /* updateDestinationFrame */);
- update(sc, width, height, format);
- }
-
public BLASTBufferQueue(String name, boolean updateDestinationFrame) {
mNativeObject = nativeCreate(name, updateDestinationFrame);
}
diff --git a/graphics/java/android/graphics/OWNERS b/graphics/java/android/graphics/OWNERS
index ef8d26cc65b9..1ea197658f93 100644
--- a/graphics/java/android/graphics/OWNERS
+++ b/graphics/java/android/graphics/OWNERS
@@ -2,10 +2,10 @@
romainguy@google.com
jreck@google.com
-njawad@google.com
sumir@google.com
djsollen@google.com
-scroggo@google.com
+alecmouri@google.com
+sallyqi@google.com
per-file BLASTBufferQueue.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file FontFamily.java = file:fonts/OWNERS
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index e6c652c14c71..5e93f8db9388 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -20,6 +20,7 @@ import static android.security.keystore2.AndroidKeyStoreCipherSpiBase.DEFAULT_MG
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.content.Context;
import android.hardware.security.keymint.EcCurve;
import android.hardware.security.keymint.KeyParameter;
@@ -732,6 +733,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
}
}
+ @RequiresPermission(value = android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ conditional = true)
private void addAttestationParameters(@NonNull List<KeyParameter> params)
throws ProviderException, IllegalArgumentException, DeviceIdAttestationException {
byte[] challenge = mSpec.getAttestationChallenge();
@@ -824,7 +827,13 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
break;
}
case AttestationUtils.ID_TYPE_MEID: {
- final String meid = telephonyService.getMeid(0);
+ String meid;
+ try {
+ meid = telephonyService.getMeid(0);
+ } catch (UnsupportedOperationException e) {
+ Log.e(TAG, "Unable to retrieve MEID", e);
+ meid = null;
+ }
if (meid == null) {
throw new DeviceIdAttestationException("Unable to retrieve MEID");
}
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 957d1b835ec2..bcb6c4f555f7 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -170,9 +170,9 @@ android_library {
"res",
],
static_libs: [
+ "//frameworks/base/packages/SystemUI/aconfig:com_android_systemui_flags_lib",
"//frameworks/libs/systemui:com_android_systemui_shared_flags_lib",
"//frameworks/libs/systemui:iconloader_base",
- "//packages/apps/Car/SystemUI/aconfig:com_android_systemui_car_flags_lib",
"PlatformAnimationLib",
"WindowManager-Shell-lite-proto",
"WindowManager-Shell-proto",
diff --git a/libs/WindowManager/Shell/AndroidManifest.xml b/libs/WindowManager/Shell/AndroidManifest.xml
index 4f1cd9780f8b..9c15319585b7 100644
--- a/libs/WindowManager/Shell/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/AndroidManifest.xml
@@ -32,7 +32,7 @@
<activity
android:name=".desktopmode.DesktopWallpaperActivity"
android:excludeFromRecents="true"
- android:launchMode="singleInstance"
+ android:launchMode="singleInstancePerTask"
android:showForAllUsers="true"
android:theme="@style/DesktopWallpaperTheme" />
diff --git a/libs/WindowManager/Shell/aconfig/Android.bp b/libs/WindowManager/Shell/aconfig/Android.bp
index 7f8f57b172ff..f8da7fa86cff 100644
--- a/libs/WindowManager/Shell/aconfig/Android.bp
+++ b/libs/WindowManager/Shell/aconfig/Android.bp
@@ -4,6 +4,7 @@ aconfig_declarations {
container: "system",
srcs: [
"multitasking.aconfig",
+ "automotive.aconfig",
],
}
diff --git a/libs/WindowManager/Shell/aconfig/automotive.aconfig b/libs/WindowManager/Shell/aconfig/automotive.aconfig
new file mode 100644
index 000000000000..2f25aa460ec1
--- /dev/null
+++ b/libs/WindowManager/Shell/aconfig/automotive.aconfig
@@ -0,0 +1,11 @@
+# proto-file: build/make/tools/aconfig/aconfig_protos/protos/aconfig.proto
+
+package: "com.android.wm.shell"
+container: "system"
+
+flag {
+ name: "enable_auto_task_stack_controller"
+ namespace: "multitasking"
+ description: "Enables auto task stack controller to manage task stacks on automotive"
+ bug: "384082238"
+}
diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
index 688bf83224aa..b10b099c970b 100644
--- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig
+++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
@@ -13,13 +13,6 @@ flag {
}
flag {
- name: "enable_split_contextual"
- namespace: "multitasking"
- description: "Enables invoking split contextually"
- bug: "276361926"
-}
-
-flag {
name: "enable_taskbar_navbar_unification"
namespace: "multitasking"
description: "Enables taskbar / navbar unification"
@@ -104,6 +97,13 @@ flag {
}
flag {
+ name: "enable_create_any_bubble"
+ namespace: "multitasking"
+ description: "Enable UI affordances to create bubbles via launcher app icons"
+ bug: "385220199"
+}
+
+flag {
name: "only_reuse_bubbled_task_when_launched_from_bubble"
namespace: "multitasking"
description: "Allow reusing bubbled tasks for new activities only when launching from bubbles"
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt
index c62d2a06bad5..90ea7d35015e 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt
@@ -34,7 +34,6 @@ import com.android.internal.protolog.ProtoLog
import com.android.internal.statusbar.IStatusBarService
import com.android.wm.shell.Flags
import com.android.wm.shell.ShellTaskOrganizer
-import com.android.wm.shell.TestShellExecutor
import com.android.wm.shell.bubbles.Bubbles.SysuiProxy
import com.android.wm.shell.bubbles.properties.ProdBubbleProperties
import com.android.wm.shell.bubbles.storage.BubblePersistentRepository
@@ -44,6 +43,7 @@ import com.android.wm.shell.common.DisplayInsetsController
import com.android.wm.shell.common.FloatingContentCoordinator
import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.common.TaskStackListenerImpl
+import com.android.wm.shell.common.TestShellExecutor
import com.android.wm.shell.draganddrop.DragAndDropController
import com.android.wm.shell.shared.TransactionPool
import com.android.wm.shell.shared.bubbles.BubbleBarLocation
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt
index ab2e552c7a3d..a7eebd6159e4 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt
@@ -36,10 +36,10 @@ import com.android.internal.protolog.ProtoLog
import com.android.launcher3.icons.BubbleIconFactory
import com.android.wm.shell.Flags
import com.android.wm.shell.R
-import com.android.wm.shell.TestShellExecutor
import com.android.wm.shell.bubbles.Bubbles.SysuiProxy
import com.android.wm.shell.bubbles.animation.AnimatableScaleMatrix
import com.android.wm.shell.common.FloatingContentCoordinator
+import com.android.wm.shell.common.TestShellExecutor
import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils
import com.google.common.truth.Truth.assertThat
import com.google.common.util.concurrent.MoreExecutors.directExecutor
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskTest.kt
index 3043e2bcb0be..a83327bbadee 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskTest.kt
@@ -35,7 +35,6 @@ import com.android.internal.protolog.ProtoLog
import com.android.internal.statusbar.IStatusBarService
import com.android.launcher3.icons.BubbleIconFactory
import com.android.wm.shell.ShellTaskOrganizer
-import com.android.wm.shell.TestShellExecutor
import com.android.wm.shell.bubbles.properties.BubbleProperties
import com.android.wm.shell.bubbles.storage.BubblePersistentRepository
import com.android.wm.shell.common.DisplayController
@@ -44,6 +43,7 @@ import com.android.wm.shell.common.DisplayInsetsController
import com.android.wm.shell.common.FloatingContentCoordinator
import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.common.TaskStackListenerImpl
+import com.android.wm.shell.common.TestShellExecutor
import com.android.wm.shell.shared.TransactionPool
import com.android.wm.shell.sysui.ShellCommandHandler
import com.android.wm.shell.sysui.ShellController
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/FakeBubbleFactory.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/FakeBubbleFactory.kt
index bcaa63bfad36..750178678785 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/FakeBubbleFactory.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/FakeBubbleFactory.kt
@@ -22,9 +22,9 @@ import android.content.res.Resources
import android.view.LayoutInflater
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.wm.shell.R
-import com.android.wm.shell.TestShellExecutor
import com.android.wm.shell.bubbles.BubbleViewInfoTask.BubbleViewInfo
import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView
+import com.android.wm.shell.common.TestShellExecutor
import com.google.common.util.concurrent.MoreExecutors.directExecutor
/** Helper to create a [Bubble] instance */
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt
index c45f6903c2e1..9e58b5be9d0d 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt
@@ -36,7 +36,6 @@ import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.internal.protolog.ProtoLog
-import com.android.wm.shell.TestShellExecutor
import com.android.wm.shell.bubbles.Bubble
import com.android.wm.shell.bubbles.BubbleExpandedViewManager
import com.android.wm.shell.bubbles.BubbleLogger
@@ -46,6 +45,7 @@ import com.android.wm.shell.bubbles.BubbleTaskView
import com.android.wm.shell.bubbles.DeviceConfig
import com.android.wm.shell.bubbles.FakeBubbleExpandedViewManager
import com.android.wm.shell.bubbles.FakeBubbleFactory
+import com.android.wm.shell.common.TestShellExecutor
import com.android.wm.shell.taskview.TaskView
import com.android.wm.shell.taskview.TaskViewTaskController
import com.google.common.truth.Truth.assertThat
@@ -290,11 +290,10 @@ class BubbleBarAnimationHelperTest {
assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue()
- val bbevBottom = bbev.contentBottomOnScreen + bubblePositioner.insets.top
activityScenario.onActivity {
// notify that the IME top coordinate is greater than the bottom of the expanded view.
// there's no overlap so it should not be clipped.
- animationHelper.onImeTopChanged(bbevBottom * 2)
+ animationHelper.onImeTopChanged(bbev.contentBottomOnScreen * 2)
}
val outline = Outline()
bbev.outlineProvider.getOutline(bbev, outline)
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt
index bfc798bb9c79..fbbcff2dee92 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt
@@ -33,7 +33,6 @@ import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.R
-import com.android.wm.shell.TestShellExecutor
import com.android.wm.shell.bubbles.Bubble
import com.android.wm.shell.bubbles.BubbleExpandedViewManager
import com.android.wm.shell.bubbles.BubbleLogger
@@ -44,6 +43,7 @@ import com.android.wm.shell.bubbles.DeviceConfig
import com.android.wm.shell.bubbles.FakeBubbleExpandedViewManager
import com.android.wm.shell.bubbles.RegionSamplingProvider
import com.android.wm.shell.bubbles.UiEventSubject.Companion.assertThat
+import com.android.wm.shell.common.TestShellExecutor
import com.android.wm.shell.shared.handles.RegionSamplingHelper
import com.android.wm.shell.taskview.TaskView
import com.android.wm.shell.taskview.TaskViewTaskController
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt
index 9b1645e9534c..5c5dde7da351 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt
@@ -36,7 +36,6 @@ import com.android.internal.protolog.ProtoLog
import com.android.internal.statusbar.IStatusBarService
import com.android.wm.shell.R
import com.android.wm.shell.ShellTaskOrganizer
-import com.android.wm.shell.TestShellExecutor
import com.android.wm.shell.bubbles.Bubble
import com.android.wm.shell.bubbles.BubbleController
import com.android.wm.shell.bubbles.BubbleData
@@ -58,6 +57,7 @@ import com.android.wm.shell.common.DisplayInsetsController
import com.android.wm.shell.common.FloatingContentCoordinator
import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.common.TaskStackListenerImpl
+import com.android.wm.shell.common.TestShellExecutor
import com.android.wm.shell.shared.TransactionPool
import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils
import com.android.wm.shell.shared.bubbles.BubbleBarLocation
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/TestShellExecutor.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/common/TestShellExecutor.kt
index ef8e71c2590b..6b549b42cdcd 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/TestShellExecutor.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/common/TestShellExecutor.kt
@@ -14,9 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell
-
-import com.android.wm.shell.common.ShellExecutor
+package com.android.wm.shell.common
/**
* Simple implementation of [ShellExecutor] that collects all runnables and executes them
diff --git a/libs/WindowManager/Shell/res/layout/bubble_bar_manage_education.xml b/libs/WindowManager/Shell/res/layout/bubble_bar_manage_education.xml
index 7347fbad5f5d..fc8b29912955 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_bar_manage_education.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_bar_manage_education.xml
@@ -38,7 +38,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/bubble_popup_text_margin"
android:maxWidth="@dimen/bubble_popup_content_max_width"
- android:maxLines="1"
+ android:maxLines="2"
android:ellipsize="end"
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Headline"
android:textColor="@androidprv:color/materialColorOnSurface"
diff --git a/libs/WindowManager/Shell/res/layout/bubble_bar_stack_education.xml b/libs/WindowManager/Shell/res/layout/bubble_bar_stack_education.xml
index f0e1871168dd..1616707954f5 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_bar_stack_education.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_bar_stack_education.xml
@@ -38,7 +38,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/bubble_popup_text_margin"
android:maxWidth="@dimen/bubble_popup_content_max_width"
- android:maxLines="1"
+ android:maxLines="2"
android:ellipsize="end"
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Headline"
android:textColor="@androidprv:color/materialColorOnSurface"
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index 6f18eda13caf..cf9c18b43a5e 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -23,7 +23,7 @@
<string name="pip_menu_title" msgid="5393619322111827096">"תפריט"</string>
<string name="pip_menu_accessibility_title" msgid="8129016817688656249">"תפריט \'תמונה בתוך תמונה\'"</string>
<string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> במצב תמונה בתוך תמונה"</string>
- <string name="pip_notification_message" msgid="8854051911700302620">"אם אינך רוצה שהתכונה הזו תשמש את <xliff:g id="NAME">%s</xliff:g>, יש להקיש כדי לפתוח את ההגדרות ולהשבית את התכונה."</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"אם אינך רוצה שהתכונה הזו תשמש את <xliff:g id="NAME">%s</xliff:g>, יש ללחוץ כדי לפתוח את ההגדרות ולהשבית את התכונה."</string>
<string name="pip_play" msgid="3496151081459417097">"הפעלה"</string>
<string name="pip_pause" msgid="690688849510295232">"השהיה"</string>
<string name="pip_skip_to_next" msgid="8403429188794867653">"אפשר לדלג אל הבא"</string>
@@ -53,7 +53,7 @@
<string name="accessibility_split_top" msgid="2789329702027147146">"פיצול למעלה"</string>
<string name="accessibility_split_bottom" msgid="8694551025220868191">"פיצול למטה"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"איך להשתמש בתכונה \'מצב שימוש ביד אחת\'"</string>
- <string name="one_handed_tutorial_description" msgid="3486582858591353067">"כדי לצאת, יש להחליק למעלה מתחתית המסך או להקיש במקום כלשהו במסך מעל האפליקציה"</string>
+ <string name="one_handed_tutorial_description" msgid="3486582858591353067">"כדי לצאת, יש להחליק למעלה מתחתית המסך או ללחוץ במקום כלשהו במסך מעל האפליקציה"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"הפעלה של מצב שימוש ביד אחת"</string>
<string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"יציאה ממצב שימוש ביד אחת"</string>
<string name="bubbles_settings_button_description" msgid="1301286017420516912">"הגדרות לבועות של <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
@@ -76,33 +76,33 @@
<string name="bubble_fullscreen_text" msgid="1006758103218086231">"הצגה במסך מלא"</string>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"אין להציג בועות לשיחה"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"לדבר בבועות"</string>
- <string name="bubbles_user_education_description" msgid="4215862563054175407">"שיחות חדשות מופיעות כסמלים צפים, או בועות. יש להקיש כדי לפתוח בועה. יש לגרור כדי להזיז אותה."</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"שיחות חדשות מופיעות כסמלים צפים, או בועות. יש ללחוץ כדי לפתוח בועה. יש לגרור כדי להזיז אותה."</string>
<string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"שליטה בבועות, בכל זמן"</string>
- <string name="bubbles_user_education_manage" msgid="3460756219946517198">"יש להקיש על \'ניהול\' כדי להשבית את הבועות מהאפליקציה הזו"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"יש ללחוץ על \'ניהול\' כדי להשבית את הבועות מהאפליקציה הזו"</string>
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"הבנתי"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"אין בועות מהזמן האחרון"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"בועות אחרונות ובועות שנסגרו יופיעו כאן"</string>
<string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"צ\'אט בבועות"</string>
- <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"שיחות חדשות מופיעות כסמלים בפינה התחתונה של המסך. אפשר להקיש כדי להרחיב אותן או לגרור כדי לסגור אותן."</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"שיחות חדשות מופיעות כסמלים בפינה התחתונה של המסך. אפשר ללחוץ כדי להרחיב אותן או לגרור כדי לסגור אותן."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"שליטה בבועות בכל זמן"</string>
- <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"אפשר להקיש כאן כדי לקבוע אילו אפליקציות ושיחות יוכלו להופיע בבועות"</string>
+ <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"אפשר ללחוץ כאן כדי לקבוע אילו אפליקציות ושיחות יוכלו להופיע בבועות"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"בועה"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"ניהול"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"הבועה נסגרה."</string>
<string name="bubble_shortcut_label" msgid="666269077944378311">"בועות"</string>
<string name="bubble_shortcut_long_label" msgid="6088437544312894043">"הצגת הבועות"</string>
- <string name="restart_button_description" msgid="4564728020654658478">"כדי לראות טוב יותר יש להקיש ולהפעיל את האפליקציה הזו מחדש"</string>
+ <string name="restart_button_description" msgid="4564728020654658478">"כדי לראות טוב יותר יש ללחוץ ולהפעיל את האפליקציה הזו מחדש"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"אפשר לשנות את יחס הגובה-רוחב של האפליקציה הזו ב\'הגדרות\'"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"שינוי יחס גובה-רוחב"</string>
- <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"בעיות במצלמה?\nאפשר להקיש כדי לבצע התאמה מחדש"</string>
- <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"הבעיה לא נפתרה?\nאפשר להקיש כדי לחזור לגרסה הקודמת"</string>
- <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"אין בעיות במצלמה? אפשר להקיש כדי לסגור."</string>
+ <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"בעיות במצלמה?\nאפשר ללחוץ כדי לבצע התאמה מחדש"</string>
+ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"הבעיה לא נפתרה?\nאפשר ללחוץ כדי לחזור לגרסה הקודמת"</string>
+ <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"אין בעיות במצלמה? אפשר ללחוץ כדי לסגור."</string>
<string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"תפריט האפליקציה נמצא כאן"</string>
<string name="windowing_desktop_mode_image_button_education_tooltip" msgid="2523468503353474095">"כדי לפתוח כמה אפליקציות יחד, צריך לעבור למצב תצוגה למחשב"</string>
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"אפשר לחזור למסך מלא בכל שלב מתפריט האפליקציה"</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>
@@ -110,7 +110,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-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 9e0f107f7e55..abc4d08cd3ca 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -25,7 +25,7 @@
<string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> చిత్రంలో చిత్రం రూపంలో ఉంది"</string>
<string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> ఈ లక్షణాన్ని ఉపయోగించకూడదు అని మీరు అనుకుంటే, సెట్టింగ్‌లను తెరవడానికి ట్యాప్ చేసి, దీన్ని ఆఫ్ చేయండి."</string>
<string name="pip_play" msgid="3496151081459417097">"ప్లే చేయి"</string>
- <string name="pip_pause" msgid="690688849510295232">"పాజ్ చేయి"</string>
+ <string name="pip_pause" msgid="690688849510295232">"పాజ్ చేయండి"</string>
<string name="pip_skip_to_next" msgid="8403429188794867653">"దాటవేసి తర్వాత దానికి వెళ్లు"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"దాటవేసి మునుపటి దానికి వెళ్లు"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"సైజ్‌ మార్చు"</string>
diff --git a/libs/WindowManager/Shell/shared/Android.bp b/libs/WindowManager/Shell/shared/Android.bp
index c3ee0f76f550..d7669ed5cf34 100644
--- a/libs/WindowManager/Shell/shared/Android.bp
+++ b/libs/WindowManager/Shell/shared/Android.bp
@@ -56,6 +56,7 @@ android_library {
static_libs: [
"androidx.core_core-animation",
"androidx.dynamicanimation_dynamicanimation",
+ "com_android_wm_shell_flags_lib",
"jsr330",
],
kotlincflags: ["-Xjvm-default=all"],
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java
index e033f673d07d..840de2c86f92 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java
@@ -40,7 +40,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
-import android.app.TaskInfo;
import android.app.WindowConfiguration;
import android.graphics.Rect;
import android.util.ArrayMap;
@@ -57,6 +56,9 @@ public class TransitionUtil {
/** Flag applied to a transition change to identify it as a divider bar for animation. */
public static final int FLAG_IS_DIVIDER_BAR = FLAG_FIRST_CUSTOM;
+ /** Flag applied to a transition change to identify it as a desktop wallpaper activity. */
+ public static final int FLAG_IS_DESKTOP_WALLPAPER_ACTIVITY = FLAG_FIRST_CUSTOM << 1;
+
/** @return true if the transition was triggered by opening something vs closing something */
public static boolean isOpeningType(@WindowManager.TransitionType int type) {
return type == TRANSIT_OPEN
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleAnythingFlagHelper.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleAnythingFlagHelper.java
new file mode 100644
index 000000000000..e1f1d0c32eb0
--- /dev/null
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleAnythingFlagHelper.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.shared.bubbles;
+
+import com.android.wm.shell.Flags;
+
+/**
+ * Bubble anything has some dependent flags, this class simplifies the checks.
+ * (TODO: b/389737359 - remove this when the feature is launched).
+ */
+public class BubbleAnythingFlagHelper {
+
+ private BubbleAnythingFlagHelper() {}
+
+ /** Whether creating any bubble or the overall bubble anything feature is enabled. */
+ public static boolean enableCreateAnyBubble() {
+ return enableBubbleAnything() || Flags.enableCreateAnyBubble();
+ }
+
+ /**
+ * Whether creating any bubble and transforming to fullscreen, or the overall bubble anything
+ * feature is enabled.
+ */
+ public static boolean enableBubbleToFullscreen() {
+ return enableBubbleAnything()
+ || (Flags.enableBubbleToFullscreen()
+ && Flags.enableCreateAnyBubble());
+ }
+
+ /** Whether the overall bubble anything feature is enabled. */
+ public static boolean enableBubbleAnything() {
+ return Flags.enableBubbleAnything();
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/appzoomout/AppZoomOutController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/appzoomout/AppZoomOutController.java
index 8cd7b0f48003..10023c9dba40 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/appzoomout/AppZoomOutController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/appzoomout/AppZoomOutController.java
@@ -16,7 +16,9 @@
package com.android.wm.shell.appzoomout;
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.systemui.Flags.spatialModelAppPushback;
import android.app.ActivityManager;
import android.app.WindowConfiguration;
@@ -92,7 +94,9 @@ public class AppZoomOutController implements RemoteCallable<AppZoomOutController
mDisplayAreaOrganizer = displayAreaOrganizer;
mMainExecutor = mainExecutor;
- shellInit.addInitCallback(this::onInit, this);
+ if (spatialModelAppPushback()) {
+ shellInit.addInitCallback(this::onInit, this);
+ }
}
private void onInit() {
@@ -100,6 +104,7 @@ public class AppZoomOutController implements RemoteCallable<AppZoomOutController
mDisplayController.addDisplayWindowListener(mDisplaysChangedListener);
mDisplayController.addDisplayChangingController(this);
+ updateDisplayLayout(mContext.getDisplayId());
mDisplayAreaOrganizer.registerOrganizer();
}
@@ -135,7 +140,9 @@ public class AppZoomOutController implements RemoteCallable<AppZoomOutController
public void onDisplayChange(int displayId, int fromRotation, int toRotation,
@Nullable DisplayAreaInfo newDisplayAreaInfo, WindowContainerTransaction wct) {
// TODO: verify if there is synchronization issues.
- mDisplayAreaOrganizer.onRotateDisplay(mContext, toRotation);
+ if (toRotation != ROTATION_UNDEFINED) {
+ mDisplayAreaOrganizer.onRotateDisplay(mContext, toRotation);
+ }
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/AutoTaskStackControllerImpl.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/AutoTaskStackControllerImpl.kt
index f8f284238a98..8171312762ef 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/AutoTaskStackControllerImpl.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/AutoTaskStackControllerImpl.kt
@@ -33,7 +33,7 @@ import android.view.WindowManager.TRANSIT_CHANGE
import android.window.TransitionInfo
import android.window.TransitionRequestInfo
import android.window.WindowContainerTransaction
-import com.android.systemui.car.Flags.autoTaskStackWindowing
+import com.android.wm.shell.Flags.enableAutoTaskStackController
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.common.ShellExecutor
@@ -66,7 +66,7 @@ class AutoTaskStackControllerImpl @Inject constructor(
private val defaultRootTaskPerDisplay = mutableMapOf<Int, Int>()
init {
- if (!autoTaskStackWindowing()) {
+ if (!enableAutoTaskStackController()) {
throw IllegalStateException("Failed to initialize" +
"AutoTaskStackController as the auto_task_stack_windowing TS flag is disabled.")
} else {
@@ -220,7 +220,7 @@ class AutoTaskStackControllerImpl @Inject constructor(
displayId: Int,
listener: RootTaskStackListener
) {
- if (!autoTaskStackWindowing()) {
+ if (!enableAutoTaskStackController()) {
Slog.e(
TAG, "Failed to create root task stack as the " +
"auto_task_stack_windowing TS flag is disabled."
@@ -236,7 +236,7 @@ class AutoTaskStackControllerImpl @Inject constructor(
}
override fun setDefaultRootTaskStackOnDisplay(displayId: Int, rootTaskStackId: Int?) {
- if (!autoTaskStackWindowing()) {
+ if (!enableAutoTaskStackController()) {
Slog.e(
TAG, "Failed to set default root task stack as the " +
"auto_task_stack_windowing TS flag is disabled."
@@ -280,7 +280,7 @@ class AutoTaskStackControllerImpl @Inject constructor(
}
override fun startTransition(transaction: AutoTaskStackTransaction): IBinder? {
- if (!autoTaskStackWindowing()) {
+ if (!enableAutoTaskStackController()) {
Slog.e(
TAG, "Failed to start transaction as the " +
"auto_task_stack_windowing TS flag is disabled."
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
index 862906a11424..62995319db80 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
@@ -136,23 +136,15 @@ class BubbleOverflow(private val context: Context, private val positioner: Bubbl
// Update bitmap
val fg = InsetDrawable(overflowBtn?.iconDrawable, overflowIconInset)
- bitmap =
- iconFactory
- .createBadgedIconBitmap(AdaptiveIconDrawable(ColorDrawable(colorAccent), fg))
- .icon
+ val drawable = AdaptiveIconDrawable(ColorDrawable(colorAccent), fg)
+ bitmap = iconFactory.createBadgedIconBitmap(drawable).icon
// Update dot path
dotPath =
PathParser.createPathFromPathData(
res.getString(com.android.internal.R.string.config_icon_mask)
)
- val scale =
- iconFactory.normalizer.getScale(
- iconView!!.iconDrawable,
- null /* outBounds */,
- null /* path */,
- null /* outMaskShape */
- )
+ val scale = iconFactory.normalizer.getScale(iconView!!.iconDrawable)
val radius = BadgedImageView.DEFAULT_PATH_SIZE / 2f
val matrix = Matrix()
matrix.setScale(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index e073b02dc630..ac5b9c9866ed 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -674,9 +674,7 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
if (mTaskView != null) {
mTaskView.getBoundsOnScreen(mTempBounds);
}
- // return the bottom of the content rect, adjusted for insets so the result is in screen
- // coordinate
- return mTempBounds.bottom + mPositioner.getInsets().top;
+ return mTempBounds.bottom;
}
/** Update the amount by which to clip the expanded view at the bottom. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index eb1e72790a25..c9890a5b4963 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -447,8 +447,10 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
}
}
- private int imeTop(float surfaceOffset) {
- return mImeFrame.top + (int) surfaceOffset;
+ private int imeTop(float surfaceOffset, float surfacePositionY) {
+ // surfaceOffset is already offset by the surface's top inset, so we need to subtract
+ // the top inset so that the return value is in screen coordinates.
+ return mImeFrame.top + (int) (surfaceOffset - surfacePositionY);
}
private boolean calcIsFloating(InsetsSource imeSource) {
@@ -581,7 +583,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
final float alpha = (mAnimateAlpha || isFloating)
? (value - hiddenY) / (shownY - hiddenY) : 1f;
t.setAlpha(animatingLeash, alpha);
- dispatchPositionChanged(mDisplayId, imeTop(value), t);
+ dispatchPositionChanged(mDisplayId, imeTop(value, defaultY), t);
t.apply();
mTransactionPool.release(t);
});
@@ -600,11 +602,12 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
t.setPosition(animatingLeash, x, value);
if (DEBUG) {
Slog.d(TAG, "onAnimationStart d:" + mDisplayId + " top:"
- + imeTop(hiddenY) + "->" + imeTop(shownY)
+ + imeTop(hiddenY, defaultY) + "->" + imeTop(shownY, defaultY)
+ " showing:" + (mAnimationDirection == DIRECTION_SHOW));
}
- int flags = dispatchStartPositioning(mDisplayId, imeTop(hiddenY),
- imeTop(shownY), mAnimationDirection == DIRECTION_SHOW, isFloating, t);
+ int flags = dispatchStartPositioning(mDisplayId, imeTop(hiddenY, defaultY),
+ imeTop(shownY, defaultY), mAnimationDirection == DIRECTION_SHOW,
+ isFloating, t);
mAnimateAlpha = (flags & ImePositionProcessor.IME_ANIMATION_NO_ALPHA) == 0;
final float alpha = (mAnimateAlpha || isFloating)
? (value - hiddenY) / (shownY - hiddenY)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt
index cdfa14bbc4e2..9b9988457808 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.desktopmode
+import com.android.window.flags.Flags
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource.UNKNOWN
import com.android.wm.shell.sysui.ShellCommandHandler
import java.io.PrintWriter
@@ -26,35 +27,28 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
override fun onShellCommand(args: Array<String>, pw: PrintWriter): Boolean =
when (args[0]) {
- "moveToDesktop" -> {
- if (!runMoveToDesktop(args, pw)) {
- pw.println("Task not found. Please enter a valid taskId.")
- false
- } else {
- true
- }
- }
- "moveToNextDisplay" -> {
- if (!runMoveToNextDisplay(args, pw)) {
- pw.println("Task not found. Please enter a valid taskId.")
- false
- } else {
- true
- }
- }
+ "moveTaskToDesk" -> runMoveTaskToDesk(args, pw)
+ "moveToNextDisplay" -> runMoveToNextDisplay(args, pw)
+ "createDesk" -> runCreateDesk(args, pw)
+ "activateDesk" -> runActivateDesk(args, pw)
+ "removeDesk" -> runRemoveDesk(args, pw)
+ "removeAllDesks" -> runRemoveAllDesks(args, pw)
+ "moveTaskToFront" -> runMoveTaskToFront(args, pw)
+ "moveTaskOutOfDesk" -> runMoveTaskOutOfDesk(args, pw)
+ "canCreateDesk" -> runCanCreateDesk(args, pw)
+ "getActiveDeskId" -> runGetActiveDeskId(args, pw)
else -> {
pw.println("Invalid command: ${args[0]}")
false
}
}
- private fun runMoveToDesktop(args: Array<String>, pw: PrintWriter): Boolean {
+ private fun runMoveTaskToDesk(args: Array<String>, pw: PrintWriter): Boolean {
if (args.size < 2) {
// First argument is the action name.
pw.println("Error: task id should be provided as arguments")
return false
}
-
val taskId =
try {
args[1].toInt()
@@ -62,7 +56,22 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
pw.println("Error: task id should be an integer")
return false
}
- return controller.moveTaskToDesktop(taskId, transitionSource = UNKNOWN)
+ if (!Flags.enableMultipleDesktopsBackend()) {
+ return controller.moveTaskToDesktop(taskId, transitionSource = UNKNOWN)
+ }
+ if (args.size < 3) {
+ pw.println("Error: desk id should be provided as arguments")
+ return false
+ }
+ val deskId =
+ try {
+ args[2].toInt()
+ } catch (e: NumberFormatException) {
+ pw.println("Error: desk id should be an integer")
+ return false
+ }
+ pw.println("Not implemented.")
+ return false
}
private fun runMoveToNextDisplay(args: Array<String>, pw: PrintWriter): Boolean {
@@ -84,10 +93,184 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
return true
}
+ private fun runCreateDesk(args: Array<String>, pw: PrintWriter): Boolean {
+ if (!Flags.enableMultipleDesktopsBackend()) {
+ pw.println("Not supported.")
+ return false
+ }
+ if (args.size < 2) {
+ // First argument is the action name.
+ pw.println("Error: desk id should be provided as arguments")
+ return false
+ }
+ val displayId =
+ try {
+ args[1].toInt()
+ } catch (e: NumberFormatException) {
+ pw.println("Error: display id should be an integer")
+ return false
+ }
+ pw.println("Not implemented.")
+ return false
+ }
+
+ private fun runActivateDesk(args: Array<String>, pw: PrintWriter): Boolean {
+ if (!Flags.enableMultipleDesktopsBackend()) {
+ pw.println("Not supported.")
+ return false
+ }
+ if (args.size < 2) {
+ // First argument is the action name.
+ pw.println("Error: desk id should be provided as arguments")
+ return false
+ }
+ val deskId =
+ try {
+ args[1].toInt()
+ } catch (e: NumberFormatException) {
+ pw.println("Error: desk id should be an integer")
+ return false
+ }
+ pw.println("Not implemented.")
+ return false
+ }
+
+ private fun runRemoveDesk(args: Array<String>, pw: PrintWriter): Boolean {
+ if (!Flags.enableMultipleDesktopsBackend()) {
+ pw.println("Not supported.")
+ return false
+ }
+ if (args.size < 2) {
+ // First argument is the action name.
+ pw.println("Error: desk id should be provided as arguments")
+ return false
+ }
+ val deskId =
+ try {
+ args[1].toInt()
+ } catch (e: NumberFormatException) {
+ pw.println("Error: desk id should be an integer")
+ return false
+ }
+ pw.println("Not implemented.")
+ return false
+ }
+
+ private fun runRemoveAllDesks(args: Array<String>, pw: PrintWriter): Boolean {
+ if (!Flags.enableMultipleDesktopsBackend()) {
+ pw.println("Not supported.")
+ return false
+ }
+ pw.println("Not implemented.")
+ return false
+ }
+
+ private fun runMoveTaskToFront(args: Array<String>, pw: PrintWriter): Boolean {
+ if (!Flags.enableMultipleDesktopsBackend()) {
+ pw.println("Not supported.")
+ return false
+ }
+ if (args.size < 2) {
+ // First argument is the action name.
+ pw.println("Error: task id should be provided as arguments")
+ return false
+ }
+ val taskId =
+ try {
+ args[1].toInt()
+ } catch (e: NumberFormatException) {
+ pw.println("Error: task id should be an integer")
+ return false
+ }
+ pw.println("Not implemented.")
+ return false
+ }
+
+ private fun runMoveTaskOutOfDesk(args: Array<String>, pw: PrintWriter): Boolean {
+ if (!Flags.enableMultipleDesktopsBackend()) {
+ pw.println("Not supported.")
+ return false
+ }
+ if (args.size < 2) {
+ // First argument is the action name.
+ pw.println("Error: task id should be provided as arguments")
+ return false
+ }
+ val taskId =
+ try {
+ args[1].toInt()
+ } catch (e: NumberFormatException) {
+ pw.println("Error: task id should be an integer")
+ return false
+ }
+ pw.println("Not implemented.")
+ return false
+ }
+
+ private fun runCanCreateDesk(args: Array<String>, pw: PrintWriter): Boolean {
+ if (!Flags.enableMultipleDesktopsBackend()) {
+ pw.println("Not supported.")
+ return false
+ }
+ val displayId =
+ try {
+ args[1].toInt()
+ } catch (e: NumberFormatException) {
+ pw.println("Error: display id should be an integer")
+ return false
+ }
+ pw.println("Not implemented.")
+ return false
+ }
+
+ private fun runGetActiveDeskId(args: Array<String>, pw: PrintWriter): Boolean {
+ if (!Flags.enableMultipleDesktopsBackend()) {
+ pw.println("Not supported.")
+ return false
+ }
+ if (args.size < 2) {
+ // First argument is the action name.
+ pw.println("Error: task id should be provided as arguments")
+ return false
+ }
+ val displayId =
+ try {
+ args[1].toInt()
+ } catch (e: NumberFormatException) {
+ pw.println("Error: display id should be an integer")
+ return false
+ }
+ pw.println("Not implemented.")
+ return false
+ }
+
override fun printShellCommandHelp(pw: PrintWriter, prefix: String) {
- pw.println("$prefix moveToDesktop <taskId> ")
- pw.println("$prefix Move a task with given id to desktop mode.")
- pw.println("$prefix moveToNextDisplay <taskId> ")
+ if (!Flags.enableMultipleDesktopsBackend()) {
+ pw.println("$prefix moveTaskToDesk <taskId> ")
+ pw.println("$prefix Move a task with given id to desktop mode.")
+ pw.println("$prefix moveToNextDisplay <taskId> ")
+ pw.println("$prefix Move a task with given id to next display.")
+ return
+ }
+ pw.println("$prefix moveTaskToDesk <taskId> <deskId>")
+ pw.println("$prefix Move a task with given id to the given desk and activate it.")
+ pw.println("$prefix moveToNextDisplay <taskId>")
pw.println("$prefix Move a task with given id to next display.")
+ pw.println("$prefix createDesk <displayId>")
+ pw.println("$prefix Creates a desk on the given display.")
+ pw.println("$prefix activateDesk <deskId>")
+ pw.println("$prefix Activates the given desk.")
+ pw.println("$prefix removeDesk <deskId> ")
+ pw.println("$prefix Removes the given desk and all of its windows.")
+ pw.println("$prefix removeAllDesks")
+ pw.println("$prefix Removes all the desks and their windows across all displays")
+ pw.println("$prefix moveTaskToFront <taskId>")
+ pw.println("$prefix Moves a task in front of its siblings.")
+ pw.println("$prefix moveTaskOutOfDesk <taskId>")
+ pw.println("$prefix Moves the given desktop task out of the desk into fullscreen mode.")
+ pw.println("$prefix canCreateDesk <displayId>")
+ pw.println("$prefix Whether creating a new desk in the given display is allowed.")
+ pw.println("$prefix getActivateDeskId <displayId>")
+ pw.println("$prefix Print the id of the active desk in the given display.")
}
}
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 73d15270c811..f38957e48dbf 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
@@ -552,7 +552,11 @@ class DesktopTasksController(
)
val wct = WindowContainerTransaction()
exitSplitIfApplicable(wct, taskInfo)
- moveHomeTask(wct, toTop = true)
+ if (Flags.enablePerDisplayDesktopWallpaperActivity()) {
+ moveHomeTask(wct, toTop = true, taskInfo.displayId)
+ } else {
+ moveHomeTask(wct, toTop = true)
+ }
val taskIdToMinimize =
bringDesktopAppsToFrontBeforeShowingNewTask(taskInfo.displayId, wct, taskInfo.taskId)
addMoveToDesktopChanges(wct, taskInfo)
@@ -1309,11 +1313,15 @@ class DesktopTasksController(
): Int? {
logV("bringDesktopAppsToFront, newTaskId=%d", newTaskIdInFront)
// Move home to front, ensures that we go back home when all desktop windows are closed
- moveHomeTask(wct, toTop = true)
+ if (Flags.enablePerDisplayDesktopWallpaperActivity()) {
+ moveHomeTask(wct, toTop = true, displayId)
+ } else {
+ moveHomeTask(wct, toTop = true)
+ }
// Currently, we only handle the desktop on the default display really.
if (
- (displayId == DEFAULT_DISPLAY || Flags.enableBugFixesForSecondaryDisplay()) &&
+ (displayId == DEFAULT_DISPLAY || Flags.enablePerDisplayDesktopWallpaperActivity()) &&
ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
) {
// Add translucent wallpaper activity to show the wallpaper underneath
@@ -1359,9 +1367,13 @@ class DesktopTasksController(
return taskIdToMinimize
}
- private fun moveHomeTask(wct: WindowContainerTransaction, toTop: Boolean) {
+ private fun moveHomeTask(
+ wct: WindowContainerTransaction,
+ toTop: Boolean,
+ displayId: Int = DEFAULT_DISPLAY,
+ ) {
shellTaskOrganizer
- .getRunningTasks(context.displayId)
+ .getRunningTasks(displayId)
.firstOrNull { task -> task.activityType == ACTIVITY_TYPE_HOME }
?.let { homeTask -> wct.reorder(homeTask.getToken(), /* onTop= */ toTop) }
}
@@ -1370,12 +1382,19 @@ class DesktopTasksController(
logV("addWallpaperActivity")
if (Flags.enableDesktopWallpaperActivityForSystemUser()) {
val intent = Intent(context, DesktopWallpaperActivity::class.java)
+ if (
+ desktopWallpaperActivityTokenProvider.getToken(displayId) == null &&
+ Flags.enablePerDisplayDesktopWallpaperActivity()
+ ) {
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
+ }
val options =
ActivityOptions.makeBasic().apply {
launchWindowingMode = WINDOWING_MODE_FULLSCREEN
pendingIntentBackgroundActivityStartMode =
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS
- if (Flags.enableBugFixesForSecondaryDisplay()) {
+ if (Flags.enablePerDisplayDesktopWallpaperActivity()) {
launchDisplayId = displayId
}
}
@@ -1391,13 +1410,20 @@ class DesktopTasksController(
val userHandle = UserHandle.of(userId)
val userContext = context.createContextAsUser(userHandle, /* flags= */ 0)
val intent = Intent(userContext, DesktopWallpaperActivity::class.java)
+ if (
+ desktopWallpaperActivityTokenProvider.getToken(displayId) == null &&
+ Flags.enablePerDisplayDesktopWallpaperActivity()
+ ) {
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
+ }
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId)
val options =
ActivityOptions.makeBasic().apply {
launchWindowingMode = WINDOWING_MODE_FULLSCREEN
pendingIntentBackgroundActivityStartMode =
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS
- if (Flags.enableBugFixesForSecondaryDisplay()) {
+ if (Flags.enablePerDisplayDesktopWallpaperActivity()) {
launchDisplayId = displayId
}
}
@@ -1414,8 +1440,8 @@ class DesktopTasksController(
}
}
- private fun removeWallpaperActivity(wct: WindowContainerTransaction) {
- desktopWallpaperActivityTokenProvider.getToken()?.let { token ->
+ private fun removeWallpaperActivity(wct: WindowContainerTransaction, displayId: Int) {
+ desktopWallpaperActivityTokenProvider.getToken(displayId)?.let { token ->
logV("removeWallpaperActivity")
if (Flags.enableDesktopWallpaperActivityForSystemUser()) {
wct.reorder(token, /* onTop= */ false)
@@ -1440,9 +1466,6 @@ class DesktopTasksController(
if (!taskRepository.isOnlyVisibleNonClosingTask(taskId, displayId)) {
return
}
- if (displayId != DEFAULT_DISPLAY) {
- return
- }
} else if (
Flags.enableDesktopWindowingPip() &&
taskRepository.isMinimizedPipPresentInDisplay(displayId) &&
@@ -1457,7 +1480,7 @@ class DesktopTasksController(
desktopModeEnterExitTransitionListener?.onExitDesktopModeTransitionStarted(
FULLSCREEN_ANIMATION_DURATION
)
- removeWallpaperActivity(wct)
+ removeWallpaperActivity(wct, displayId)
}
fun releaseVisualIndicator() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
index b9a65fee7d4d..14c8429766cc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
@@ -60,7 +60,9 @@ class DesktopTasksTransitionObserver(
shellInit: ShellInit,
) : Transitions.TransitionObserver {
- private var transitionToCloseWallpaper: IBinder? = null
+ data class CloseWallpaperTransition(val transition: IBinder, val displayId: Int)
+
+ private var transitionToCloseWallpaper: CloseWallpaperTransition? = null
/* Pending PiP transition and its associated display id and task id. */
private var pendingPipTransitionAndPipTask: Triple<IBinder, Int, Int>? = null
private var currentProfileId: Int
@@ -248,9 +250,10 @@ class DesktopTasksTransitionObserver(
desktopRepository.getVisibleTaskCount(taskInfo.displayId) == 0 &&
change.mode == TRANSIT_CLOSE &&
taskInfo.windowingMode == WINDOWING_MODE_FREEFORM &&
- desktopWallpaperActivityTokenProvider.getToken() != null
+ desktopWallpaperActivityTokenProvider.getToken(taskInfo.displayId) != null
) {
- transitionToCloseWallpaper = transition
+ transitionToCloseWallpaper =
+ CloseWallpaperTransition(transition, taskInfo.displayId)
currentProfileId = taskInfo.userId
}
}
@@ -265,25 +268,28 @@ class DesktopTasksTransitionObserver(
}
override fun onTransitionFinished(transition: IBinder, aborted: Boolean) {
+ val lastSeenTransitionToCloseWallpaper = transitionToCloseWallpaper
// TODO: b/332682201 Update repository state
- if (transitionToCloseWallpaper == transition) {
+ if (lastSeenTransitionToCloseWallpaper?.transition == transition) {
// TODO: b/362469671 - Handle merging the animation when desktop is also closing.
- desktopWallpaperActivityTokenProvider.getToken()?.let { wallpaperActivityToken ->
- if (Flags.enableDesktopWallpaperActivityForSystemUser()) {
- transitions.startTransition(
- TRANSIT_TO_BACK,
- WindowContainerTransaction()
- .reorder(wallpaperActivityToken, /* onTop= */ false),
- null,
- )
- } else {
- transitions.startTransition(
- TRANSIT_CLOSE,
- WindowContainerTransaction().removeTask(wallpaperActivityToken),
- null,
- )
+ desktopWallpaperActivityTokenProvider
+ .getToken(lastSeenTransitionToCloseWallpaper.displayId)
+ ?.let { wallpaperActivityToken ->
+ if (Flags.enableDesktopWallpaperActivityForSystemUser()) {
+ transitions.startTransition(
+ TRANSIT_TO_BACK,
+ WindowContainerTransaction()
+ .reorder(wallpaperActivityToken, /* onTop= */ false),
+ null,
+ )
+ } else {
+ transitions.startTransition(
+ TRANSIT_CLOSE,
+ WindowContainerTransaction().removeTask(wallpaperActivityToken),
+ null,
+ )
+ }
}
- }
transitionToCloseWallpaper = null
} else if (pendingPipTransitionAndPipTask?.first == transition) {
val desktopRepository = desktopUserRepositories.getProfile(currentProfileId)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index 6e7740dc13e3..91150b0070ce 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -129,6 +129,20 @@ public abstract class PipTransitionController implements Transitions.TransitionH
}
/**
+ * Called when the Shell wants to start an exit-via-expand from Pip transition/animation.
+ */
+ public void startExpandTransition(WindowContainerTransaction out) {
+ // Default implementation does nothing.
+ }
+
+ /**
+ * Called when the Shell wants to start a remove Pip transition/animation.
+ */
+ public void startRemoveTransition(boolean withFadeout) {
+ // Default implementation does nothing.
+ }
+
+ /**
* Called when the Shell wants to start resizing Pip transition/animation.
*
* @param duration the suggested duration for resize animation.
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 9babe9e9e4eb..e22cd37ab4b7 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
@@ -344,13 +344,22 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
*/
@Override
public void dismissPip() {
+ dismissPip(true /* withFadeout */);
+ }
+
+ /**
+ * Dismisses the pinned stack.
+ *
+ * @param withFadeout should animate with fadeout for the removal
+ */
+ public void dismissPip(boolean withFadeout) {
if (DEBUG) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: removePip: callers=\n%s", TAG, Debug.getCallers(5, " "));
}
cancelPhysicsAnimation();
mMenuController.hideMenu(ANIM_TYPE_DISMISS, false /* resize */);
- mPipScheduler.scheduleRemovePip();
+ mPipScheduler.scheduleRemovePip(withFadeout);
}
/** Sets the movement bounds to use to constrain PIP position animations. */
@@ -473,7 +482,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
mPipBoundsState.getMovementBounds().bottom + getBounds().height() * 2,
0,
mSpringConfig)
- .withEndActions(this::dismissPip);
+ .withEndActions(() -> dismissPip(false /* withFadeout */));
startBoundsAnimator(
getBounds().left /* toX */, getBounds().bottom + getBounds().height() /* toY */);
@@ -772,7 +781,6 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
case PipTransitionState.EXITING_PIP:
// We need to force finish any local animators if about to leave PiP, to avoid
// breaking the state (e.g. leashes are cleaned up upon exit).
- if (!mPipBoundsState.getMotionBoundsState().isInMotion()) break;
cancelPhysicsAnimation();
settlePipBoundsAfterPhysicsAnimation(false /* animatingAfter */);
break;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
index ea8dac982703..ed532cad0523 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
@@ -19,9 +19,6 @@ package com.android.wm.shell.pip2.phone;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
-import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
-
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Rect;
@@ -112,19 +109,6 @@ public class PipScheduler {
return wct;
}
- @Nullable
- private WindowContainerTransaction getRemovePipTransaction() {
- WindowContainerToken pipTaskToken = mPipTransitionState.getPipTaskToken();
- if (pipTaskToken == null) {
- return null;
- }
- WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.setBounds(pipTaskToken, null);
- wct.setWindowingMode(pipTaskToken, WINDOWING_MODE_UNDEFINED);
- wct.reorder(pipTaskToken, false);
- return wct;
- }
-
/**
* Schedules exit PiP via expand transition.
*/
@@ -133,21 +117,16 @@ public class PipScheduler {
if (!mPipTransitionState.isInPip()) return;
WindowContainerTransaction wct = getExitPipViaExpandTransaction();
if (wct != null) {
- mPipTransitionController.startExitTransition(TRANSIT_EXIT_PIP, wct,
- null /* destinationBounds */);
+ mPipTransitionController.startExpandTransition(wct);
}
});
}
/** Schedules remove PiP transition. */
- public void scheduleRemovePip() {
+ public void scheduleRemovePip(boolean withFadeout) {
mMainExecutor.execute(() -> {
if (!mPipTransitionState.isInPip()) return;
- WindowContainerTransaction wct = getRemovePipTransaction();
- if (wct != null) {
- mPipTransitionController.startExitTransition(TRANSIT_REMOVE_PIP, wct,
- null /* destinationBounds */);
- }
+ mPipTransitionController.startRemoveTransition(withFadeout);
});
}
@@ -216,9 +195,11 @@ public class PipScheduler {
* @param degrees the angle to rotate the bounds to.
*/
public void scheduleUserResizePip(Rect toBounds, float degrees) {
- if (toBounds.isEmpty()) {
+ if (toBounds.isEmpty() || !mPipTransitionState.isInPip()) {
ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
- "%s: Attempted to user resize PIP to empty bounds, aborting.", TAG);
+ "%s: Attempted to user resize PIP in invalid state, aborting;"
+ + "toBounds=%s, mPipTransitionState=%s",
+ TAG, toBounds, mPipTransitionState);
return;
}
SurfaceControl leash = mPipTransitionState.getPinnedTaskLeash();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index 0a42c71ce095..4902455cae16 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -18,6 +18,7 @@ package com.android.wm.shell.pip2.phone;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
@@ -126,6 +127,7 @@ public class PipTransition extends PipTransitionController implements
@Nullable
private IBinder mResizeTransition;
private int mBoundsChangeDuration = BOUNDS_CHANGE_JUMPCUT_DURATION;
+ private boolean mPendingRemoveWithFadeout;
//
@@ -184,15 +186,19 @@ public class PipTransition extends PipTransitionController implements
//
@Override
- public void startExitTransition(int type, WindowContainerTransaction out,
- @Nullable Rect destinationBounds) {
- if (out == null) {
- return;
- }
- IBinder transition = mTransitions.startTransition(type, out, this);
- if (type == TRANSIT_EXIT_PIP) {
- mExitViaExpandTransition = transition;
- }
+ public void startExpandTransition(WindowContainerTransaction out) {
+ if (out == null) return;
+ mPipTransitionState.setState(PipTransitionState.EXITING_PIP);
+ mExitViaExpandTransition = mTransitions.startTransition(TRANSIT_EXIT_PIP, out, this);
+ }
+
+ @Override
+ public void startRemoveTransition(boolean withFadeout) {
+ final WindowContainerTransaction wct = getRemovePipTransaction();
+ if (wct == null) return;
+ mPipTransitionState.setState(PipTransitionState.EXITING_PIP);
+ mPendingRemoveWithFadeout = withFadeout;
+ mTransitions.startTransition(TRANSIT_REMOVE_PIP, wct, this);
}
@Override
@@ -284,7 +290,6 @@ public class PipTransition extends PipTransitionController implements
finishCallback);
} else if (transition == mExitViaExpandTransition) {
mExitViaExpandTransition = null;
- mPipTransitionState.setState(PipTransitionState.EXITING_PIP);
return startExpandAnimation(info, startTransaction, finishTransaction, finishCallback);
} else if (transition == mResizeTransition) {
mResizeTransition = null;
@@ -690,11 +695,19 @@ public class PipTransition extends PipTransitionController implements
TransitionInfo.Change pipChange = getChangeByToken(info,
mPipTransitionState.getPipTaskToken());
mFinishCallback = finishCallback;
- PipAlphaAnimator animator = new PipAlphaAnimator(mContext, pipChange.getLeash(),
- startTransaction, PipAlphaAnimator.FADE_OUT);
+
finishTransaction.setAlpha(pipChange.getLeash(), 0f);
- animator.setAnimationEndCallback(this::finishTransition);
- animator.start();
+ if (mPendingRemoveWithFadeout) {
+ PipAlphaAnimator animator = new PipAlphaAnimator(mContext, pipChange.getLeash(),
+ startTransaction, PipAlphaAnimator.FADE_OUT);
+ animator.setAnimationEndCallback(this::finishTransition);
+ animator.start();
+ } else {
+ // Jumpcut to a faded-out PiP if no fadeout animation was requested.
+ startTransaction.setAlpha(pipChange.getLeash(), 0f);
+ startTransaction.apply();
+ finishTransition();
+ }
return true;
}
@@ -824,6 +837,19 @@ public class PipTransition extends PipTransitionController implements
return wct;
}
+ @Nullable
+ private WindowContainerTransaction getRemovePipTransaction() {
+ WindowContainerToken pipTaskToken = mPipTransitionState.getPipTaskToken();
+ if (pipTaskToken == null) {
+ return null;
+ }
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.setBounds(pipTaskToken, null);
+ wct.setWindowingMode(pipTaskToken, WINDOWING_MODE_UNDEFINED);
+ wct.reorder(pipTaskToken, false);
+ return wct;
+ }
+
private boolean isAutoEnterInButtonNavigation(@NonNull TransitionRequestInfo requestInfo) {
final ActivityManager.RunningTaskInfo pipTask = requestInfo.getPipChange() != null
? requestInfo.getPipChange().getTaskInfo() : null;
@@ -1000,6 +1026,7 @@ public class PipTransition extends PipTransitionController implements
}
mPipTransitionState.setPinnedTaskLeash(null);
mPipTransitionState.setPipTaskInfo(null);
+ mPendingRemoveWithFadeout = false;
break;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
index 6f9f40a487c7..8805cbb0dfbd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
@@ -27,7 +27,9 @@ import android.window.WindowContainerToken;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.Preconditions;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.annotations.ShellMainThread;
import java.io.PrintWriter;
@@ -201,6 +203,13 @@ public class PipTransitionState {
Preconditions.checkArgument(extra != null && !extra.isEmpty(),
"No extra bundle for " + stateToString(state) + " state.");
}
+ if (!shouldTransitionToState(state)) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Attempted to transition to an invalid state=%s, while in %s",
+ TAG, stateToString(state), this);
+ return;
+ }
+
if (mState != state) {
final int prevState = mState;
mState = state;
@@ -374,6 +383,17 @@ public class PipTransitionState {
return ++mPrevCustomState;
}
+ private boolean shouldTransitionToState(@TransitionState int newState) {
+ switch (newState) {
+ case SCHEDULED_BOUNDS_CHANGE:
+ // Allow scheduling bounds change only while in PiP, except for if another bounds
+ // change was scheduled but hasn't started playing yet.
+ return isInPip();
+ default:
+ return true;
+ }
+ }
+
private static String stateToString(int state) {
switch (state) {
case UNDEFINED: return "undefined";
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index d6f9183a4281..0182588398a4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -54,7 +54,6 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.internal.protolog.ProtoLog;
-import com.android.launcher3.Flags;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
@@ -103,6 +102,7 @@ public class RecentTasksController implements TaskStackListenerCallback,
private final RecentTasksImpl mImpl = new RecentTasksImpl();
private final ActivityTaskManager mActivityTaskManager;
private final TaskStackTransitionObserver mTaskStackTransitionObserver;
+ private final RecentsShellCommandHandler mRecentsShellCommandHandler;
private RecentsTransitionHandler mTransitionHandler = null;
private IRecentTasksListener mListener;
private final boolean mPcFeatureEnabled;
@@ -167,6 +167,7 @@ public class RecentTasksController implements TaskStackListenerCallback,
mDesktopUserRepositories = desktopUserRepositories;
mTaskStackTransitionObserver = taskStackTransitionObserver;
mMainExecutor = mainExecutor;
+ mRecentsShellCommandHandler = new RecentsShellCommandHandler(this);
shellInit.addInitCallback(this::onInit, this);
}
@@ -183,6 +184,7 @@ public class RecentTasksController implements TaskStackListenerCallback,
mShellController.addExternalInterface(IRecentTasks.DESCRIPTOR,
this::createExternalInterface, this);
mShellCommandHandler.addDumpCallback(this::dump, this);
+ mShellCommandHandler.addCommandCallback("recents", mRecentsShellCommandHandler, this);
mUserId = ActivityManager.getCurrentUser();
mDesktopUserRepositories.ifPresent(
desktopUserRepositories ->
@@ -550,9 +552,7 @@ public class RecentTasksController implements TaskStackListenerCallback,
groupedTasks.add(GroupedTaskInfo.forSplitTasks(taskInfo, pairedTaskInfo,
mTaskSplitBoundsMap.get(pairedTaskId)));
} else {
- if (
- Flags.enableUseTopVisibleActivityForExcludeFromRecentTask()
- && isWallpaperTask(taskInfo)) {
+ if (isWallpaperTask(taskInfo)) {
// Don't add the wallpaper task as an entry in grouped tasks
continue;
}
@@ -656,6 +656,11 @@ public class RecentTasksController implements TaskStackListenerCallback,
return mActivityTaskManager.removeTask(taskId);
}
+ /** Removes all recent tasks that are visible. */
+ public void removeAllVisibleRecentTasks() throws RemoteException {
+ ActivityTaskManager.getService().removeAllVisibleRecentTasks();
+ }
+
public void dump(@NonNull PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsShellCommandHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsShellCommandHandler.kt
new file mode 100644
index 000000000000..f786e079ed93
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsShellCommandHandler.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.recents
+
+import android.os.RemoteException
+import com.android.wm.shell.sysui.ShellCommandHandler.ShellCommandActionHandler
+import java.io.PrintWriter
+
+class RecentsShellCommandHandler(
+ private val recentTasksController: RecentTasksController
+) : ShellCommandActionHandler {
+ override fun onShellCommand(args: Array<out String>, pw: PrintWriter): Boolean {
+ when (args[0]) {
+ "clearAll" -> return runClearAll(pw)
+ else -> {
+ pw.println("Invalid command: " + args[0])
+ return false
+ }
+ }
+ }
+
+ override fun printShellCommandHelp(pw: PrintWriter, prefix: String) {
+ pw.println("${prefix}clearAll")
+ pw.println("$prefix Clears all visible recent tasks.")
+ }
+
+ private fun runClearAll(pw: PrintWriter): Boolean {
+ try {
+ recentTasksController.removeAllVisibleRecentTasks()
+ } catch (e: RemoteException) {
+ pw.println("Exception while removing visible recent tasks:")
+ e.printStackTrace(pw)
+ return false
+ }
+ return true
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index c27ef295db51..c9136b4ad18d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -929,8 +929,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
for (int taskId : taskIds) {
ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId);
if (task != null) {
- wct.setWindowingMode(task.token, WINDOWING_MODE_UNDEFINED)
- .setBounds(task.token, null);
+ wct.setWindowingMode(task.getToken(), WINDOWING_MODE_UNDEFINED)
+ .setBounds(task.getToken(), null);
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 81f444ba2af3..c5994f83429a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -633,7 +633,7 @@ public class SplashscreenContentDrawer {
private class ShapeIconFactory extends BaseIconFactory {
protected ShapeIconFactory(Context context, int fillResIconDpi, int iconBitmapSize) {
- super(context, fillResIconDpi, iconBitmapSize, true /* shapeDetection */);
+ super(context, fillResIconDpi, iconBitmapSize);
}
}
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 8dd14983e122..5c7dd078ee45 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
@@ -536,9 +536,12 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
}
return;
}
+ // Cache it to avoid NPE and make sure to remove it from recents history.
+ // mTaskToken can be cleared in onTaskVanished() when the task is removed.
+ final WindowContainerToken taskToken = mTaskToken;
mShellExecutor.execute(() -> {
WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.removeTask(mTaskToken);
+ wct.removeTask(taskToken);
mTaskViewTransitions.closeTaskView(wct, this);
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/FocusTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/FocusTransitionObserver.java
index 6d01e247b48d..e04682a4b86f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/FocusTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/FocusTransitionObserver.java
@@ -17,6 +17,8 @@
package com.android.wm.shell.transition;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP;
@@ -66,36 +68,45 @@ public class FocusTransitionObserver {
if (!enableDisplayFocusInShellTransitions()) {
return;
}
+ final SparseArray<RunningTaskInfo> lastTransitionFocusedTasks =
+ mFocusedTaskOnDisplay.clone();
+
final List<TransitionInfo.Change> changes = info.getChanges();
for (int i = changes.size() - 1; i >= 0; i--) {
final TransitionInfo.Change change = changes.get(i);
final RunningTaskInfo task = change.getTaskInfo();
- if (task != null
- && (change.hasFlags(FLAG_MOVED_TO_TOP) || change.getMode() == TRANSIT_OPEN)) {
- final RunningTaskInfo lastFocusedTaskOnDisplay =
- mFocusedTaskOnDisplay.get(task.displayId);
- if (lastFocusedTaskOnDisplay != null) {
- mTmpTasksToBeNotified.add(lastFocusedTaskOnDisplay);
+ if (task != null) {
+ if (change.hasFlags(FLAG_MOVED_TO_TOP) || change.getMode() == TRANSIT_OPEN) {
+ updateFocusedTaskPerDisplay(task, task.displayId);
+ } else {
+ // Update focus assuming that any task moved to another display is focused in
+ // the new display.
+ // TODO(sahok): remove this logic when b/388665104 is fixed
+ final boolean isBeyondDisplay = change.getStartDisplayId() != INVALID_DISPLAY
+ && change.getEndDisplayId() != INVALID_DISPLAY
+ && change.getStartDisplayId() != change.getEndDisplayId();
+
+ RunningTaskInfo lastTransitionFocusedTaskOnStartDisplay =
+ lastTransitionFocusedTasks.get(change.getStartDisplayId());
+ final boolean isLastTransitionFocused =
+ lastTransitionFocusedTaskOnStartDisplay != null
+ && task.taskId
+ == lastTransitionFocusedTaskOnStartDisplay.taskId;
+ if (change.getMode() == TRANSIT_CHANGE && isBeyondDisplay
+ && isLastTransitionFocused) {
+ // The task have moved to another display and keeps its focus.
+ // MOVE_TO_TOP is not reported but we need to update the focused task in
+ // the end display.
+ updateFocusedTaskPerDisplay(task, change.getEndDisplayId());
+ }
}
- mTmpTasksToBeNotified.add(task);
- mFocusedTaskOnDisplay.put(task.displayId, task);
}
+
if (change.hasFlags(FLAG_IS_DISPLAY) && change.hasFlags(FLAG_MOVED_TO_TOP)) {
if (mFocusedDisplayId != change.getEndDisplayId()) {
- final RunningTaskInfo lastGloballyFocusedTask =
- mFocusedTaskOnDisplay.get(mFocusedDisplayId);
- if (lastGloballyFocusedTask != null) {
- mTmpTasksToBeNotified.add(lastGloballyFocusedTask);
- }
- mFocusedDisplayId = change.getEndDisplayId();
- notifyFocusedDisplayChanged();
- final RunningTaskInfo currentGloballyFocusedTask =
- mFocusedTaskOnDisplay.get(mFocusedDisplayId);
- if (currentGloballyFocusedTask != null) {
- mTmpTasksToBeNotified.add(currentGloballyFocusedTask);
- }
+ updateFocusedDisplay(change.getEndDisplayId());
}
}
}
@@ -103,6 +114,31 @@ public class FocusTransitionObserver {
mTmpTasksToBeNotified.clear();
}
+ private void updateFocusedTaskPerDisplay(RunningTaskInfo task, int displayId) {
+ final RunningTaskInfo lastFocusedTaskOnDisplay =
+ mFocusedTaskOnDisplay.get(displayId);
+ if (lastFocusedTaskOnDisplay != null) {
+ mTmpTasksToBeNotified.add(lastFocusedTaskOnDisplay);
+ }
+ mTmpTasksToBeNotified.add(task);
+ mFocusedTaskOnDisplay.put(displayId, task);
+ }
+
+ private void updateFocusedDisplay(int endDisplayId) {
+ final RunningTaskInfo lastGloballyFocusedTask =
+ mFocusedTaskOnDisplay.get(mFocusedDisplayId);
+ if (lastGloballyFocusedTask != null) {
+ mTmpTasksToBeNotified.add(lastGloballyFocusedTask);
+ }
+ mFocusedDisplayId = endDisplayId;
+ notifyFocusedDisplayChanged();
+ final RunningTaskInfo currentGloballyFocusedTask =
+ mFocusedTaskOnDisplay.get(mFocusedDisplayId);
+ if (currentGloballyFocusedTask != null) {
+ mTmpTasksToBeNotified.add(currentGloballyFocusedTask);
+ }
+ }
+
/**
* Sets the focus transition listener that receives any transitions resulting in focus switch.
* This is for calls from outside the Shell, within the host process.
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 d5929f010e02..abfb41bb513a 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
@@ -39,6 +39,7 @@ import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPI
import static com.android.systemui.shared.Flags.returnAnimationFrameworkLongLived;
import static com.android.window.flags.Flags.ensureWallpaperInTransitions;
+import static com.android.wm.shell.shared.TransitionUtil.FLAG_IS_DESKTOP_WALLPAPER_ACTIVITY;
import static com.android.wm.shell.shared.TransitionUtil.isClosingType;
import static com.android.wm.shell.shared.TransitionUtil.isOpeningType;
@@ -84,6 +85,7 @@ import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes;
+import com.android.wm.shell.desktopmode.DesktopWallpaperActivity;
import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.FocusTransitionListener;
@@ -795,6 +797,14 @@ public class Transitions implements RemoteCallable<Transitions>,
mReadyDuringSync.remove(active);
}
+ // If any of the changes are on DesktopWallpaperActivity, add the flag to the change.
+ for (TransitionInfo.Change change : info.getChanges()) {
+ if (change.getTaskInfo() != null
+ && DesktopWallpaperActivity.isWallpaperTask(change.getTaskInfo())) {
+ change.setFlags(FLAG_IS_DESKTOP_WALLPAPER_ACTIVITY);
+ }
+ }
+
final Track track = getOrCreateTrack(info.getTrack());
track.mReadyTransitions.add(active);
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 a90c6fbdae1d..d6d393f2500c 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
@@ -2022,7 +2022,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
Supplier<SurfaceControl.Transaction> transactionFactory,
Handler handler) {
final TaskPositioner taskPositioner = DesktopModeStatus.isVeiledResizeEnabled()
- ? new VeiledResizeTaskPositioner(
+ // TODO(b/383632995): Update when the flag is launched.
+ ? (Flags.enableConnectedDisplaysWindowDrag()
+ ? new MultiDisplayVeiledResizeTaskPositioner(
taskOrganizer,
windowDecoration,
displayController,
@@ -2030,6 +2032,14 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
transitions,
interactionJankMonitor,
handler)
+ : new VeiledResizeTaskPositioner(
+ taskOrganizer,
+ windowDecoration,
+ displayController,
+ dragEventListener,
+ transitions,
+ interactionJankMonitor,
+ handler))
: new FluidResizeTaskPositioner(
taskOrganizer,
transitions,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt
new file mode 100644
index 000000000000..8dc921c986ce
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt
@@ -0,0 +1,293 @@
+/*
+ * 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.graphics.PointF
+import android.graphics.Rect
+import android.os.Handler
+import android.os.IBinder
+import android.os.Looper
+import android.view.Choreographer
+import android.view.Surface
+import android.view.SurfaceControl
+import android.view.WindowManager
+import android.window.TransitionInfo
+import android.window.TransitionRequestInfo
+import android.window.WindowContainerTransaction
+import com.android.internal.jank.Cuj
+import com.android.internal.jank.InteractionJankMonitor
+import com.android.wm.shell.ShellTaskOrganizer
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.shared.annotations.ShellMainThread
+import com.android.wm.shell.transition.Transitions
+import java.util.concurrent.TimeUnit
+import java.util.function.Supplier
+
+/**
+ * A task positioner that also takes into account resizing a
+ * [com.android.wm.shell.windowdecor.ResizeVeil] and dragging move across multiple displays.
+ * - If the drag is resizing the task, we resize the veil instead.
+ * - If the drag is repositioning, we consider multi-display topology if needed, and update in the
+ * typical manner.
+ */
+class MultiDisplayVeiledResizeTaskPositioner(
+ private val taskOrganizer: ShellTaskOrganizer,
+ private val desktopWindowDecoration: DesktopModeWindowDecoration,
+ private val displayController: DisplayController,
+ dragEventListener: DragPositioningCallbackUtility.DragEventListener,
+ private val transactionSupplier: Supplier<SurfaceControl.Transaction>,
+ private val transitions: Transitions,
+ private val interactionJankMonitor: InteractionJankMonitor,
+ @ShellMainThread private val handler: Handler,
+) : TaskPositioner, Transitions.TransitionHandler {
+ private val dragEventListeners =
+ mutableListOf<DragPositioningCallbackUtility.DragEventListener>()
+ private val stableBounds = Rect()
+ private val taskBoundsAtDragStart = Rect()
+ private val repositionStartPoint = PointF()
+ private val repositionTaskBounds = Rect()
+ private val isResizing: Boolean
+ get() =
+ (ctrlType and DragPositioningCallback.CTRL_TYPE_TOP) != 0 ||
+ (ctrlType and DragPositioningCallback.CTRL_TYPE_BOTTOM) != 0 ||
+ (ctrlType and DragPositioningCallback.CTRL_TYPE_LEFT) != 0 ||
+ (ctrlType and DragPositioningCallback.CTRL_TYPE_RIGHT) != 0
+
+ @DragPositioningCallback.CtrlType private var ctrlType = 0
+ private var isResizingOrAnimatingResize = false
+ @Surface.Rotation private var rotation = 0
+
+ constructor(
+ taskOrganizer: ShellTaskOrganizer,
+ windowDecoration: DesktopModeWindowDecoration,
+ displayController: DisplayController,
+ dragEventListener: DragPositioningCallbackUtility.DragEventListener,
+ transitions: Transitions,
+ interactionJankMonitor: InteractionJankMonitor,
+ @ShellMainThread handler: Handler,
+ ) : this(
+ taskOrganizer,
+ windowDecoration,
+ displayController,
+ dragEventListener,
+ Supplier<SurfaceControl.Transaction> { SurfaceControl.Transaction() },
+ transitions,
+ interactionJankMonitor,
+ handler,
+ )
+
+ init {
+ dragEventListeners.add(dragEventListener)
+ }
+
+ override fun onDragPositioningStart(ctrlType: Int, displayId: Int, x: Float, y: Float): Rect {
+ this.ctrlType = ctrlType
+ taskBoundsAtDragStart.set(
+ desktopWindowDecoration.mTaskInfo.configuration.windowConfiguration.bounds
+ )
+ repositionStartPoint[x] = y
+ if (isResizing) {
+ // Capture CUJ for re-sizing window in DW mode.
+ interactionJankMonitor.begin(
+ createLongTimeoutJankConfigBuilder(Cuj.CUJ_DESKTOP_MODE_RESIZE_WINDOW)
+ )
+ if (!desktopWindowDecoration.mHasGlobalFocus) {
+ val wct = WindowContainerTransaction()
+ wct.reorder(
+ desktopWindowDecoration.mTaskInfo.token,
+ /* onTop= */ true,
+ /* includingParents= */ true,
+ )
+ taskOrganizer.applyTransaction(wct)
+ }
+ }
+ for (dragEventListener in dragEventListeners) {
+ dragEventListener.onDragStart(desktopWindowDecoration.mTaskInfo.taskId)
+ }
+ repositionTaskBounds.set(taskBoundsAtDragStart)
+ val rotation =
+ desktopWindowDecoration.mTaskInfo.configuration.windowConfiguration.displayRotation
+ if (stableBounds.isEmpty || this.rotation != rotation) {
+ this.rotation = rotation
+ displayController
+ .getDisplayLayout(desktopWindowDecoration.mDisplay.displayId)!!
+ .getStableBounds(stableBounds)
+ }
+ return Rect(repositionTaskBounds)
+ }
+
+ override fun onDragPositioningMove(displayId: Int, x: Float, y: Float): Rect {
+ check(Looper.myLooper() == handler.looper) {
+ "This method must run on the shell main thread."
+ }
+ val delta = DragPositioningCallbackUtility.calculateDelta(x, y, repositionStartPoint)
+ if (
+ isResizing &&
+ DragPositioningCallbackUtility.changeBounds(
+ ctrlType,
+ repositionTaskBounds,
+ taskBoundsAtDragStart,
+ stableBounds,
+ delta,
+ displayController,
+ desktopWindowDecoration,
+ )
+ ) {
+ if (!isResizingOrAnimatingResize) {
+ for (dragEventListener in dragEventListeners) {
+ dragEventListener.onDragMove(desktopWindowDecoration.mTaskInfo.taskId)
+ }
+ desktopWindowDecoration.showResizeVeil(repositionTaskBounds)
+ isResizingOrAnimatingResize = true
+ } else {
+ desktopWindowDecoration.updateResizeVeil(repositionTaskBounds)
+ }
+ } else if (ctrlType == DragPositioningCallback.CTRL_TYPE_UNDEFINED) {
+ // Begin window drag CUJ instrumentation only when drag position moves.
+ interactionJankMonitor.begin(
+ createLongTimeoutJankConfigBuilder(Cuj.CUJ_DESKTOP_MODE_DRAG_WINDOW)
+ )
+ val t = transactionSupplier.get()
+ DragPositioningCallbackUtility.setPositionOnDrag(
+ desktopWindowDecoration,
+ repositionTaskBounds,
+ taskBoundsAtDragStart,
+ repositionStartPoint,
+ t,
+ x,
+ y,
+ )
+ t.setFrameTimeline(Choreographer.getInstance().vsyncId)
+ t.apply()
+ }
+ return Rect(repositionTaskBounds)
+ }
+
+ override fun onDragPositioningEnd(displayId: Int, x: Float, y: Float): Rect {
+ val delta = DragPositioningCallbackUtility.calculateDelta(x, y, repositionStartPoint)
+ if (isResizing) {
+ if (taskBoundsAtDragStart != repositionTaskBounds) {
+ DragPositioningCallbackUtility.changeBounds(
+ ctrlType,
+ repositionTaskBounds,
+ taskBoundsAtDragStart,
+ stableBounds,
+ delta,
+ displayController,
+ desktopWindowDecoration,
+ )
+ desktopWindowDecoration.updateResizeVeil(repositionTaskBounds)
+ val wct = WindowContainerTransaction()
+ wct.setBounds(desktopWindowDecoration.mTaskInfo.token, repositionTaskBounds)
+ transitions.startTransition(WindowManager.TRANSIT_CHANGE, wct, this)
+ } else {
+ // If bounds haven't changed, perform necessary veil reset here as startAnimation
+ // won't be called.
+ resetVeilIfVisible()
+ }
+ interactionJankMonitor.end(Cuj.CUJ_DESKTOP_MODE_RESIZE_WINDOW)
+ } else {
+ DragPositioningCallbackUtility.updateTaskBounds(
+ repositionTaskBounds,
+ taskBoundsAtDragStart,
+ repositionStartPoint,
+ x,
+ y,
+ )
+ interactionJankMonitor.end(Cuj.CUJ_DESKTOP_MODE_DRAG_WINDOW)
+ }
+
+ ctrlType = DragPositioningCallback.CTRL_TYPE_UNDEFINED
+ taskBoundsAtDragStart.setEmpty()
+ repositionStartPoint[0f] = 0f
+ return Rect(repositionTaskBounds)
+ }
+
+ private fun resetVeilIfVisible() {
+ if (isResizingOrAnimatingResize) {
+ desktopWindowDecoration.hideResizeVeil()
+ isResizingOrAnimatingResize = false
+ }
+ }
+
+ private fun createLongTimeoutJankConfigBuilder(@Cuj.CujType cujType: Int) =
+ InteractionJankMonitor.Configuration.Builder.withSurface(
+ cujType,
+ desktopWindowDecoration.mContext,
+ desktopWindowDecoration.mTaskSurface,
+ handler,
+ )
+ .setTimeout(LONG_CUJ_TIMEOUT_MS)
+
+ override fun startAnimation(
+ transition: IBinder,
+ info: TransitionInfo,
+ startTransaction: SurfaceControl.Transaction,
+ finishTransaction: SurfaceControl.Transaction,
+ finishCallback: Transitions.TransitionFinishCallback,
+ ): Boolean {
+ for (change in info.changes) {
+ val sc = change.leash
+ val endBounds = change.endAbsBounds
+ val endPosition = change.endRelOffset
+ startTransaction
+ .setWindowCrop(sc, endBounds.width(), endBounds.height())
+ .setPosition(sc, endPosition.x.toFloat(), endPosition.y.toFloat())
+ finishTransaction
+ .setWindowCrop(sc, endBounds.width(), endBounds.height())
+ .setPosition(sc, endPosition.x.toFloat(), endPosition.y.toFloat())
+ }
+
+ startTransaction.apply()
+ resetVeilIfVisible()
+ ctrlType = DragPositioningCallback.CTRL_TYPE_UNDEFINED
+ finishCallback.onTransitionFinished(null /* wct */)
+ isResizingOrAnimatingResize = false
+ interactionJankMonitor.end(Cuj.CUJ_DESKTOP_MODE_DRAG_WINDOW)
+ return true
+ }
+
+ /**
+ * We should never reach this as this handler's transitions are only started from shell
+ * explicitly.
+ */
+ override fun handleRequest(
+ transition: IBinder,
+ request: TransitionRequestInfo,
+ ): WindowContainerTransaction? {
+ return null
+ }
+
+ override fun isResizingOrAnimating() = isResizingOrAnimatingResize
+
+ override fun addDragEventListener(
+ dragEventListener: DragPositioningCallbackUtility.DragEventListener
+ ) {
+ dragEventListeners.add(dragEventListener)
+ }
+
+ override fun removeDragEventListener(
+ dragEventListener: DragPositioningCallbackUtility.DragEventListener
+ ) {
+ dragEventListeners.remove(dragEventListener)
+ }
+
+ companion object {
+ // Timeout used for resize and drag CUJs, this is longer than the default timeout to avoid
+ // timing out in the middle of a resize or drag action.
+ private val LONG_CUJ_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(/* duration= */ 10L)
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
index e011cc08903b..d2c79d76e6c1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
@@ -53,7 +53,12 @@ import java.util.function.Supplier;
* {@link com.android.wm.shell.windowdecor.ResizeVeil}.
* If the drag is resizing the task, we resize the veil instead.
* If the drag is repositioning, we update in the typical manner.
+ * <p>
+ * @deprecated This class will be replaced by
+ * {@link com.android.wm.shell.windowdecor.MultiDisplayVeiledResizeTaskPositioner}.
+ * TODO(b/383632995): Remove this class after MultiDisplayVeiledResizeTaskPositioner is launched.
*/
+@Deprecated
public class VeiledResizeTaskPositioner implements TaskPositioner, Transitions.TransitionHandler {
// Timeout used for resize and drag CUJs, this is longer than the default timeout to avoid
// timing out in the middle of a resize or drag action.
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/CloseAllAppsWithBackNavigationLandscape.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/CloseAllAppsWithBackNavigationLandscape.kt
new file mode 100644
index 000000000000..0feb13d9dded
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/CloseAllAppsWithBackNavigationLandscape.kt
@@ -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.wm.shell.flicker
+
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.CLOSE_APP
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.CLOSE_LAST_APP
+import com.android.wm.shell.scenarios.CloseAllAppsWithBackNavigation
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class CloseAllAppsWithBackNavigationLandscape : CloseAllAppsWithBackNavigation(
+ Rotation.ROTATION_90
+) {
+ // TODO(b/390043833): Add verifications that TO_BACK transition is captured when the back
+ // navigation button is pressed.
+ @ExpectedScenarios(["CLOSE_APP", "CLOSE_LAST_APP"])
+ @Test
+ override fun closeAllAppsInDesktop() = super.closeAllAppsInDesktop()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig()
+ .use(FlickerServiceConfig.DEFAULT)
+ .use(CLOSE_APP)
+ .use(CLOSE_LAST_APP)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/CloseAllAppsWithBackNavigationPortrait.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/CloseAllAppsWithBackNavigationPortrait.kt
new file mode 100644
index 000000000000..3b77ea5e5264
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/CloseAllAppsWithBackNavigationPortrait.kt
@@ -0,0 +1,48 @@
+/*
+ * 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
+
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.CLOSE_APP
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.CLOSE_LAST_APP
+import com.android.wm.shell.scenarios.CloseAllAppsWithBackNavigation
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class CloseAllAppsWithBackNavigationPortrait : CloseAllAppsWithBackNavigation() {
+ // TODO(b/390043833): Add verifications that TO_BACK transition is captured when the back
+ // navigation button is pressed.
+ @ExpectedScenarios(["CLOSE_APP", "CLOSE_LAST_APP"])
+ @Test
+ override fun closeAllAppsInDesktop() = super.closeAllAppsInDesktop()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig()
+ .use(FlickerServiceConfig.DEFAULT)
+ .use(CLOSE_APP)
+ .use(CLOSE_LAST_APP)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/EnterDesktopWithDragExistingWindowsTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/EnterDesktopWithDragExistingWindowsTest.kt
new file mode 100644
index 000000000000..2b26bbfb68cb
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/EnterDesktopWithDragExistingWindowsTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.EnterDesktopWithDragExistingWindows
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [EnterDesktopWithDragExistingWindows]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class EnterDesktopWithDragExistingWindowsTest : EnterDesktopWithDragExistingWindows()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithBackNavigation.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithBackNavigation.kt
new file mode 100644
index 000000000000..319df49cdc03
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithBackNavigation.kt
@@ -0,0 +1,73 @@
+/*
+ * 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.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.MailAppHelper
+import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.window.flags.Flags
+import com.android.wm.shell.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 CloseAllAppsWithBackNavigation(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))
+ private val mailApp = DesktopModeAppHelper(MailAppHelper(instrumentation))
+ private val nonResizeableApp = DesktopModeAppHelper(NonResizeableAppHelper(instrumentation))
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+ Assume.assumeTrue(Flags.enableDesktopWindowingBackNavigation())
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+ testApp.enterDesktopMode(wmHelper, device)
+ mailApp.launchViaIntent(wmHelper)
+ nonResizeableApp.launchViaIntent(wmHelper)
+ }
+
+ @Test
+ open fun closeAllAppsInDesktop() {
+ nonResizeableApp.closeDesktopApp(wmHelper, device, usingBackNavigation = true)
+ mailApp.closeDesktopApp(wmHelper, device, usingBackNavigation = true)
+ testApp.closeDesktopApp(wmHelper, device, usingBackNavigation = true)
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithAppHandleMenuExistingWindows.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithAppHandleMenuExistingWindows.kt
new file mode 100644
index 000000000000..2de0830dedb5
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithAppHandleMenuExistingWindows.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.scenarios
+
+import android.platform.test.annotations.Postsubmit
+import android.app.Instrumentation
+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.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.NewTasksAppHelper
+import com.android.window.flags.Flags
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class EnterDesktopWithAppHandleMenuExistingWindows {
+
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val imeApp = ImeAppHelper(instrumentation)
+ private val newTaskApp = NewTasksAppHelper(instrumentation)
+ private val testApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation))
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+ testApp.enterDesktopMode(wmHelper, device)
+ imeApp.launchViaIntent(wmHelper)
+ newTaskApp.launchViaIntent(wmHelper)
+ testApp.launchViaIntent(wmHelper)
+ testApp.exitDesktopWithDragToTopDragZone(wmHelper, device)
+ }
+
+ @Test
+ open fun reenterDesktopWithAppHandleMenu() {
+ testApp.enterDesktopModeFromAppHandleMenu(wmHelper, device)
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ newTaskApp.exit(wmHelper)
+ imeApp.exit(wmHelper)
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDragExistingWindows.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDragExistingWindows.kt
new file mode 100644
index 000000000000..814478af67c1
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDragExistingWindows.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.scenarios
+
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.NewTasksAppHelper
+import com.android.window.flags.Flags
+import com.android.wm.shell.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("Test Base Class")
+abstract class EnterDesktopWithDragExistingWindows
+constructor(
+ val rotation: Rotation = Rotation.ROTATION_0,
+ isResizeable: Boolean = true,
+ isLandscapeApp: Boolean = true,
+) : DesktopScenarioCustomAppTestBase(isResizeable, isLandscapeApp) {
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+ private val imeApp = ImeAppHelper(instrumentation)
+ private val newTaskApp = NewTasksAppHelper(instrumentation)
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+ ChangeDisplayOrientationRule.setRotation(rotation)
+ tapl.enableTransientTaskbar(false)
+
+ testApp.enterDesktopMode(wmHelper, device)
+ imeApp.launchViaIntent(wmHelper)
+ newTaskApp.launchViaIntent(wmHelper)
+ testApp.launchViaIntent(wmHelper)
+ testApp.exitDesktopWithDragToTopDragZone(wmHelper, device)
+ }
+
+ @Test
+ open fun reenterDesktopWithDrag() {
+ // By default this method uses drag to desktop
+ testApp.enterDesktopMode(wmHelper, device)
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ newTaskApp.exit(wmHelper)
+ imeApp.exit(wmHelper)
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenUnlimitedApps.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenUnlimitedApps.kt
index 367c4a437018..16a01d570575 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenUnlimitedApps.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenUnlimitedApps.kt
@@ -17,6 +17,8 @@
package com.android.wm.shell.scenarios
import android.app.Instrumentation
+import android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK
+import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.tools.traces.parsers.WindowManagerStateHelper
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
@@ -43,7 +45,7 @@ abstract class OpenUnlimitedApps()
private val device = UiDevice.getInstance(instrumentation)
private val testApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation))
- private val mailApp = DesktopModeAppHelper(MailAppHelper(instrumentation))
+ private val mailApp = MailAppHelper(instrumentation)
private val maxNum = DesktopModeStatus.getMaxTaskLimit(instrumentation.context)
@@ -61,7 +63,12 @@ abstract class OpenUnlimitedApps()
// Launch new [openTaskNum] tasks.
for (i in 1..openTaskNum) {
- mailApp.launchViaIntent(wmHelper)
+ mailApp.launchViaIntent(
+ wmHelper,
+ mailApp.openAppIntent.apply {
+ addFlags(FLAG_ACTIVITY_MULTIPLE_TASK or FLAG_ACTIVITY_NEW_TASK)
+ }
+ )
}
}
diff --git a/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/CopyContentInSplit.kt
index ba4654260864..31d89f92f744 100644
--- a/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/CopyContentInSplit.kt
+++ b/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/CopyContentInSplit.kt
@@ -24,6 +24,7 @@ import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
import com.android.wm.shell.Utils
+import com.android.wm.shell.flicker.utils.RecentTasksUtils
import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.After
import org.junit.Before
@@ -61,7 +62,6 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0) {
@After
fun teardown() {
- primaryApp.exit(wmHelper)
- secondaryApp.exit(wmHelper)
+ RecentTasksUtils.clearAllVisibleRecentTasks(instrumentation)
}
}
diff --git a/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/DismissSplitScreenByDivider.kt
index d774a31220da..1af6cac39085 100644
--- a/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/DismissSplitScreenByDivider.kt
+++ b/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/DismissSplitScreenByDivider.kt
@@ -24,6 +24,7 @@ import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
import com.android.wm.shell.Utils
+import com.android.wm.shell.flicker.utils.RecentTasksUtils
import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.After
import org.junit.Before
@@ -74,7 +75,6 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0) {
@After
fun teardown() {
- primaryApp.exit(wmHelper)
- secondaryApp.exit(wmHelper)
+ RecentTasksUtils.clearAllVisibleRecentTasks(instrumentation)
}
}
diff --git a/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/DismissSplitScreenByGoHome.kt
index 5aa161911a9a..8ad8c7bd7a7f 100644
--- a/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/DismissSplitScreenByGoHome.kt
+++ b/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/DismissSplitScreenByGoHome.kt
@@ -24,6 +24,7 @@ import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
import com.android.wm.shell.Utils
+import com.android.wm.shell.flicker.utils.RecentTasksUtils
import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.After
import org.junit.Before
@@ -60,7 +61,6 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0) {
@After
fun teardown() {
- primaryApp.exit(wmHelper)
- secondaryApp.exit(wmHelper)
+ RecentTasksUtils.clearAllVisibleRecentTasks(instrumentation)
}
}
diff --git a/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/DragDividerToResize.kt
index 668f3678bb38..da0ace472153 100644
--- a/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/DragDividerToResize.kt
+++ b/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/DragDividerToResize.kt
@@ -24,6 +24,7 @@ import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
import com.android.wm.shell.Utils
+import com.android.wm.shell.flicker.utils.RecentTasksUtils
import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.After
import org.junit.Before
@@ -61,7 +62,6 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0) {
@After
fun teardown() {
- primaryApp.exit(wmHelper)
- secondaryApp.exit(wmHelper)
+ RecentTasksUtils.clearAllVisibleRecentTasks(instrumentation)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/RecentTasksUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/RecentTasksUtils.kt
new file mode 100644
index 000000000000..aa262f9dfd6a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/RecentTasksUtils.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.utils
+
+import android.app.Instrumentation
+
+object RecentTasksUtils {
+ fun clearAllVisibleRecentTasks(instrumentation: Instrumentation) {
+ instrumentation.uiAutomation.executeShellCommand(
+ "dumpsys activity service SystemUIService WMShell recents clearAll"
+ )
+ }
+} \ No newline at end of file
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 95ed8b4d4511..2b986d184c20 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
@@ -601,7 +601,32 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
+ @EnableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
+ Flags.FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY,
+ )
+ fun showDesktopApps_onSecondaryDisplay_desktopWallpaperEnabled_perDisplayWallpaperEnabled_shouldShowWallpaper() {
+ 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(4)
+ // Expect order to be from bottom: home, wallpaperIntent, task1, task2
+ wct.assertReorderAt(index = 0, homeTask)
+ wct.assertPendingIntentAt(index = 1, desktopWallpaperIntent)
+ wct.assertReorderAt(index = 2, task1)
+ wct.assertReorderAt(index = 3, task2)
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+ @DisableFlags(Flags.FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY)
fun showDesktopApps_onSecondaryDisplay_desktopWallpaperEnabled_shouldNotShowWallpaper() {
val homeTask = setUpHomeTask(SECOND_DISPLAY)
val task1 = setUpFreeformTask(SECOND_DISPLAY)
@@ -1775,8 +1800,35 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
+ @EnableFlags(
+ FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY,
+ Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER,
+ )
+ fun moveToNextDisplay_wallpaperOnSystemUser_reorderWallpaperToBack() {
+ // Set up two display ids
+ whenever(rootTaskDisplayAreaOrganizer.displayIds)
+ .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY))
+ // Create a mock for the target display area: second display
+ val secondDisplayArea = DisplayAreaInfo(MockToken().token(), SECOND_DISPLAY, 0)
+ whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(SECOND_DISPLAY))
+ .thenReturn(secondDisplayArea)
+ // Add a task and a wallpaper
+ val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
+
+ controller.moveToNextDisplay(task.taskId)
+
+ with(getLatestWct(type = TRANSIT_CHANGE)) {
+ val wallpaperChange =
+ hierarchyOps.find { op -> op.container == wallpaperToken.asBinder() }
+ assertNotNull(wallpaperChange)
+ assertThat(wallpaperChange.type).isEqualTo(HIERARCHY_OP_TYPE_REORDER)
+ }
+ }
+
+ @Test
@EnableFlags(FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY)
- fun moveToNextDisplay_removeWallpaper() {
+ @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER)
+ fun moveToNextDisplay_wallpaperNotOnSystemUser_removeWallpaper() {
// Set up two display ids
whenever(rootTaskDisplayAreaOrganizer.displayIds)
.thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY))
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
index c42f6c35bcb0..aef44a40fa0f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
@@ -16,14 +16,10 @@
package com.android.wm.shell.pip2.phone;
-import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
-import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
-
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.when;
import static org.mockito.kotlin.MatchersKt.eq;
@@ -124,12 +120,13 @@ public class PipSchedulerTest {
.setCallsite("PipSchedulerTest")
.build();
when(mMockPipTransitionState.getPinnedTaskLeash()).thenReturn(testLeash);
+ // PiP is in a valid state by default.
+ when(mMockPipTransitionState.isInPip()).thenReturn(true);
}
@Test
public void scheduleExitPipViaExpand_nullTaskToken_noop() {
setNullPipTaskToken();
- when(mMockPipTransitionState.isInPip()).thenReturn(true);
mPipScheduler.scheduleExitPipViaExpand();
@@ -137,14 +134,12 @@ public class PipSchedulerTest {
assertNotNull(mRunnableArgumentCaptor.getValue());
mRunnableArgumentCaptor.getValue().run();
- verify(mMockPipTransitionController, never())
- .startExitTransition(eq(TRANSIT_EXIT_PIP), any(), isNull());
+ verify(mMockPipTransitionController, never()).startExpandTransition(any());
}
@Test
public void scheduleExitPipViaExpand_exitTransitionCalled() {
setMockPipTaskToken();
- when(mMockPipTransitionState.isInPip()).thenReturn(true);
mPipScheduler.scheduleExitPipViaExpand();
@@ -152,23 +147,21 @@ public class PipSchedulerTest {
assertNotNull(mRunnableArgumentCaptor.getValue());
mRunnableArgumentCaptor.getValue().run();
- verify(mMockPipTransitionController, times(1))
- .startExitTransition(eq(TRANSIT_EXIT_PIP), any(), isNull());
+ verify(mMockPipTransitionController, times(1)).startExpandTransition(any());
}
@Test
public void removePipAfterAnimation() {
setMockPipTaskToken();
- when(mMockPipTransitionState.isInPip()).thenReturn(true);
- mPipScheduler.scheduleRemovePip();
+ mPipScheduler.scheduleRemovePip(true /* withFadeout */);
verify(mMockMainExecutor, times(1)).execute(mRunnableArgumentCaptor.capture());
assertNotNull(mRunnableArgumentCaptor.getValue());
mRunnableArgumentCaptor.getValue().run();
verify(mMockPipTransitionController, times(1))
- .startExitTransition(eq(TRANSIT_REMOVE_PIP), any(), isNull());
+ .startRemoveTransition(true /* withFadeout */);
}
@Test
@@ -192,7 +185,6 @@ public class PipSchedulerTest {
@Test
public void scheduleAnimateResizePip_boundsConfig_setsConfigAtEnd() {
setMockPipTaskToken();
- when(mMockPipTransitionState.isInPip()).thenReturn(true);
mPipScheduler.scheduleAnimateResizePip(TEST_BOUNDS, true);
@@ -233,7 +225,6 @@ public class PipSchedulerTest {
@Test
public void scheduleAnimateResizePip_resizeTransition() {
setMockPipTaskToken();
- when(mMockPipTransitionState.isInPip()).thenReturn(true);
mPipScheduler.scheduleAnimateResizePip(TEST_BOUNDS, true, TEST_RESIZE_DURATION);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTransitionStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTransitionStateTest.java
index 571ae93e1aec..fa9b5903bc3c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTransitionStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTransitionStateTest.java
@@ -110,4 +110,22 @@ public class PipTransitionStateTest extends ShellTestCase {
mPipTransitionState.setState(PipTransitionState.ENTERED_PIP);
mPipTransitionState.removePipTransitionStateChangedListener(mStateChangedListener);
}
+
+ @Test
+ public void testBoundsChangeState_notInPip() {
+ Bundle extra = new Bundle();
+ extra.putParcelable(EXTRA_ENTRY_KEY, mEmptyParcelable);
+
+ mPipTransitionState.setState(PipTransitionState.UNDEFINED);
+ mPipTransitionState.setState(PipTransitionState.SCHEDULED_BOUNDS_CHANGE, extra);
+ Assert.assertEquals(PipTransitionState.UNDEFINED, mPipTransitionState.getState());
+
+ mPipTransitionState.setState(PipTransitionState.ENTERING_PIP, extra);
+ mPipTransitionState.setState(PipTransitionState.SCHEDULED_BOUNDS_CHANGE, extra);
+ Assert.assertEquals(PipTransitionState.ENTERING_PIP, mPipTransitionState.getState());
+
+ mPipTransitionState.setState(PipTransitionState.EXITING_PIP);
+ mPipTransitionState.setState(PipTransitionState.SCHEDULED_BOUNDS_CHANGE, extra);
+ Assert.assertEquals(PipTransitionState.EXITING_PIP, mPipTransitionState.getState());
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index 7e5d6ce38c5a..28f4ea0c7ada 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -22,13 +22,13 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-import static com.android.launcher3.Flags.FLAG_ENABLE_USE_TOP_VISIBLE_ACTIVITY_FOR_EXCLUDE_FROM_RECENT_TASK;
import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE;
import static com.android.wm.shell.shared.GroupedTaskInfo.TYPE_FREEFORM;
import static com.android.wm.shell.shared.GroupedTaskInfo.TYPE_FULLSCREEN;
import static com.android.wm.shell.shared.GroupedTaskInfo.TYPE_SPLIT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -65,8 +65,8 @@ import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.view.SurfaceControl;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
@@ -253,7 +253,6 @@ public class RecentTasksControllerTest extends ShellTestCase {
t3.taskId, -1);
}
- @EnableFlags(FLAG_ENABLE_USE_TOP_VISIBLE_ACTIVITY_FOR_EXCLUDE_FROM_RECENT_TASK)
@Test
public void testGetRecentTasks_removesDesktopWallpaperActivity() {
RecentTaskInfo t1 = makeTaskInfo(1);
@@ -753,15 +752,9 @@ public class RecentTasksControllerTest extends ShellTestCase {
/**
* Helper to set the raw task list on the controller.
*/
- private ArrayList<RecentTaskInfo> setRawList(
- RecentTaskInfo... tasks) {
- ArrayList<RecentTaskInfo> rawList = new ArrayList<>();
- for (RecentTaskInfo task : tasks) {
- rawList.add(task);
- }
- doReturn(rawList).when(mActivityTaskManager).getRecentTasks(anyInt(), anyInt(),
+ private void setRawList(RecentTaskInfo... tasks) {
+ doReturn(Arrays.asList(tasks)).when(mActivityTaskManager).getRecentTasks(anyInt(), anyInt(),
anyInt());
- return rawList;
}
/**
@@ -794,8 +787,9 @@ public class RecentTasksControllerTest extends ShellTestCase {
assertNull(pair.getSplitBounds());
}
}
- assertTrue("Expected: " + Arrays.toString(expectedTaskIds)
+ assertArrayEquals("Expected: " + Arrays.toString(expectedTaskIds)
+ " Received: " + Arrays.toString(flattenedTaskIds),
- Arrays.equals(flattenedTaskIds, expectedTaskIds));
+ flattenedTaskIds,
+ expectedTaskIds);
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index 2d0ea5fdc884..7a88ace3f85f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -17,6 +17,7 @@
package com.android.wm.shell.splitscreen;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_UNDEFINED;
@@ -32,6 +33,8 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.atLeastOnce;
@@ -50,9 +53,11 @@ import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.view.SurfaceControl;
import android.window.RemoteTransition;
+import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import androidx.test.annotation.UiThreadTest;
@@ -84,6 +89,7 @@ import com.android.wm.shell.transition.Transitions;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -425,6 +431,30 @@ public class StageCoordinatorTests extends ShellTestCase {
.startFullscreenTransition(any(), any());
}
+
+ @Test
+ public void startTask_ensureWindowingModeCleared() {
+ SplitScreenTransitions splitScreenTransitions =
+ spy(mStageCoordinator.getSplitTransitions());
+ mStageCoordinator.setSplitTransitions(splitScreenTransitions);
+ ArgumentCaptor<WindowContainerTransaction> wctCaptor =
+ ArgumentCaptor.forClass(WindowContainerTransaction.class);
+ int taskId = 18;
+ IBinder binder = mock(IBinder.class);
+ ActivityManager.RunningTaskInfo rti = mock(ActivityManager.RunningTaskInfo.class);
+ WindowContainerToken mockToken = mock(WindowContainerToken.class);
+ when(mockToken.asBinder()).thenReturn(binder);
+ when(rti.getToken()).thenReturn(mockToken);
+ when(mTaskOrganizer.getRunningTaskInfo(taskId)).thenReturn(rti);
+ mStageCoordinator.startTask(taskId, SPLIT_POSITION_TOP_OR_LEFT, null /*options*/,
+ null, SPLIT_INDEX_UNDEFINED);
+ verify(splitScreenTransitions).startEnterTransition(anyInt(),
+ wctCaptor.capture(), any(), any(), anyInt(), anyBoolean());
+
+ int windowingMode = wctCaptor.getValue().getChanges().get(binder).getWindowingMode();
+ assertEquals(windowingMode, WINDOWING_MODE_UNDEFINED);
+ }
+
private Transitions createTestTransitions() {
ShellInit shellInit = new ShellInit(mMainExecutor);
final Transitions t = new Transitions(mContext, shellInit, mock(ShellController.class),
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java
index 015ea20767e9..74c2f0e6753a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java
@@ -17,7 +17,9 @@
package com.android.wm.shell.transition;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP;
@@ -127,19 +129,136 @@ public class FocusTransitionObserverTest extends ShellTestCase {
true /* isFocusedOnDisplay */, false /* isFocusedGlobally */);
}
+ @Test
+ public void testTaskFocusSwitch() throws RemoteException {
+ final SurfaceControl.Transaction tx = mock(SurfaceControl.Transaction.class);
+
+ // Open 2 tasks on the default display.
+ TransitionInfo info = mock(TransitionInfo.class);
+ final List<TransitionInfo.Change> changes = new ArrayList<>();
+ setupTaskChange(changes, 1 /* taskId */, TRANSIT_OPEN,
+ DEFAULT_DISPLAY, true /* focused */);
+ when(info.getChanges()).thenReturn(changes);
+ mFocusTransitionObserver.updateFocusState(info);
+ mShellExecutor.flushAll();
+ verify(mListener, never()).onFocusedDisplayChanged(anyInt());
+ verify(mListener, times(1)).onFocusedTaskChanged(1 /* taskId */,
+ true /* isFocusedOnDisplay */, true /* isFocusedGlobally */);
+ clearInvocations(mListener);
+ changes.clear();
+
+ setupTaskChange(changes, 2 /* taskId */, TRANSIT_OPEN,
+ DEFAULT_DISPLAY, true /* focused */);
+ when(info.getChanges()).thenReturn(changes);
+ mFocusTransitionObserver.updateFocusState(info);
+ mShellExecutor.flushAll();
+ verify(mListener, times(1)).onFocusedTaskChanged(1 /* taskId */,
+ false /* isFocusedOnDisplay */, false /* isFocusedGlobally */);
+ verify(mListener, times(1)).onFocusedTaskChanged(2 /* taskId */,
+ true /* isFocusedOnDisplay */, true /* isFocusedGlobally */);
+ clearInvocations(mListener);
+ changes.clear();
+
+ // Moving a task to front.
+ changes.clear();
+ setupTaskChange(changes, 1 /* taskId */, TRANSIT_TO_FRONT,
+ DEFAULT_DISPLAY, true /* focused */);
+ when(info.getChanges()).thenReturn(changes);
+ mFocusTransitionObserver.updateFocusState(info);
+ mShellExecutor.flushAll();
+ verify(mListener, times(1)).onFocusedTaskChanged(1 /* taskId */,
+ true /* isFocusedOnDisplay */, true /* isFocusedGlobally */);
+ verify(mListener, times(1)).onFocusedTaskChanged(2 /* taskId */,
+ false /* isFocusedOnDisplay */, false /* isFocusedGlobally */);
+ }
+
+
+ @Test
+ public void testTaskMoveToAnotherDisplay() throws RemoteException {
+ final SurfaceControl.Transaction tx = mock(SurfaceControl.Transaction.class);
+
+ // First, open a task on the default display.
+ TransitionInfo info = mock(TransitionInfo.class);
+ final List<TransitionInfo.Change> changes = new ArrayList<>();
+ setupTaskChange(changes, 1 /* taskId */, TRANSIT_OPEN,
+ DEFAULT_DISPLAY, true /* focused */);
+ when(info.getChanges()).thenReturn(changes);
+ mFocusTransitionObserver.updateFocusState(info);
+ mShellExecutor.flushAll();
+ verify(mListener, never()).onFocusedDisplayChanged(anyInt());
+ verify(mListener, times(1)).onFocusedTaskChanged(1 /* taskId */,
+ true /* isFocusedOnDisplay */, true /* isFocusedGlobally */);
+ clearInvocations(mListener);
+ changes.clear();
+
+ // Open 2 tasks on the secondary display.
+ setupTaskChange(changes, 2 /* taskId */, TRANSIT_OPEN,
+ SECONDARY_DISPLAY_ID, true /* focused */);
+ setupDisplayToTopChange(changes, SECONDARY_DISPLAY_ID);
+ when(info.getChanges()).thenReturn(changes);
+ mFocusTransitionObserver.updateFocusState(info);
+ mShellExecutor.flushAll();
+ verify(mListener, times(1))
+ .onFocusedDisplayChanged(SECONDARY_DISPLAY_ID);
+ verify(mListener, times(1)).onFocusedTaskChanged(1 /* taskId */,
+ true /* isFocusedOnDisplay */, false /* isFocusedGlobally */);
+ verify(mListener, times(1)).onFocusedTaskChanged(2 /* taskId */,
+ true /* isFocusedOnDisplay */, true /* isFocusedGlobally */);
+ clearInvocations(mListener);
+ changes.clear();
+
+ setupTaskChange(changes, 3 /* taskId */, TRANSIT_OPEN,
+ SECONDARY_DISPLAY_ID, true /* focused */);
+ setupDisplayToTopChange(changes, SECONDARY_DISPLAY_ID);
+ when(info.getChanges()).thenReturn(changes);
+ mFocusTransitionObserver.updateFocusState(info);
+ mShellExecutor.flushAll();
+ verify(mListener, times(1)).onFocusedTaskChanged(2 /* taskId */,
+ false /* isFocusedOnDisplay */, false /* isFocusedGlobally */);
+ verify(mListener, times(1)).onFocusedTaskChanged(3 /* taskId */,
+ true /* isFocusedOnDisplay */, true /* isFocusedGlobally */);
+ clearInvocations(mListener);
+ changes.clear();
+
+ // Move focused task in the secondary display to the default display
+ setupTaskChange(changes, 3 /* taskId */, TRANSIT_CHANGE,
+ SECONDARY_DISPLAY_ID, DEFAULT_DISPLAY, true /* focused */);
+ setupTaskChange(changes, 2 /* taskId */, TRANSIT_TO_FRONT,
+ SECONDARY_DISPLAY_ID, true /* focused */);
+ setupDisplayToTopChange(changes, DEFAULT_DISPLAY);
+ when(info.getChanges()).thenReturn(changes);
+ mFocusTransitionObserver.updateFocusState(info);
+ mShellExecutor.flushAll();
+ verify(mListener, times(1)).onFocusedTaskChanged(1 /* taskId */,
+ false /* isFocusedOnDisplay */, false /* isFocusedGlobally */);
+ verify(mListener, times(1)).onFocusedTaskChanged(2 /* taskId */,
+ true /* isFocusedOnDisplay */, false /* isFocusedGlobally */);
+ verify(mListener, times(1)).onFocusedTaskChanged(3 /* taskId */,
+ true /* isFocusedOnDisplay */, true /* isFocusedGlobally */);
+ clearInvocations(mListener);
+ }
+
private void setupTaskChange(List<TransitionInfo.Change> changes, int taskId,
@TransitionMode int mode, int displayId, boolean focused) {
+ setupTaskChange(changes, taskId, mode, displayId, displayId, focused);
+ }
+
+ private void setupTaskChange(List<TransitionInfo.Change> changes, int taskId,
+ @TransitionMode int mode, int startDisplayId, int endDisplayId, boolean focused) {
TransitionInfo.Change change = mock(TransitionInfo.Change.class);
RunningTaskInfo taskInfo = mock(RunningTaskInfo.class);
taskInfo.taskId = taskId;
taskInfo.isFocused = focused;
when(change.hasFlags(FLAG_MOVED_TO_TOP)).thenReturn(focused);
- taskInfo.displayId = displayId;
+ taskInfo.displayId = endDisplayId;
+ when(change.getStartDisplayId()).thenReturn(startDisplayId);
+ when(change.getEndDisplayId()).thenReturn(endDisplayId);
when(change.getTaskInfo()).thenReturn(taskInfo);
when(change.getMode()).thenReturn(mode);
changes.add(change);
}
+
private void setupDisplayToTopChange(List<TransitionInfo.Change> changes, int displayId) {
TransitionInfo.Change change = mock(TransitionInfo.Change.class);
when(change.hasFlags(FLAG_MOVED_TO_TOP)).thenReturn(true);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index dd645fd968e4..0a19be4eb959 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -1781,6 +1781,7 @@ public class ShellTransitionTests extends ShellTestCase {
taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
taskInfo.configuration.windowConfiguration.setActivityType(activityType);
taskInfo.token = mock(WindowContainerToken.class);
+ taskInfo.baseIntent = mock(Intent.class);
return taskInfo;
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
index 8af8285d031c..b44af4733fd2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
@@ -182,6 +182,7 @@ open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() {
spyContext.addMockSystemService(InputManager::class.java, mockInputManager)
desktopModeEventLogger = mock<DesktopModeEventLogger>()
whenever(mockDesktopUserRepositories.current).thenReturn(mockDesktopRepository)
+ whenever(mockDisplayController.getDisplayContext(any())).thenReturn(spyContext)
whenever(mockDesktopUserRepositories.getProfile(anyInt()))
.thenReturn(mockDesktopRepository)
desktopModeWindowDecorViewModel = DesktopModeWindowDecorViewModel(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt
new file mode 100644
index 000000000000..f179cac32244
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt
@@ -0,0 +1,611 @@
+/*
+ * 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.Context
+import android.content.res.Resources
+import android.graphics.Point
+import android.graphics.Rect
+import android.os.Handler
+import android.os.IBinder
+import android.os.Looper
+import android.testing.AndroidTestingRunner
+import android.view.Display
+import android.view.Surface.ROTATION_0
+import android.view.Surface.ROTATION_270
+import android.view.Surface.ROTATION_90
+import android.view.SurfaceControl
+import android.view.SurfaceControl.Transaction
+import android.view.WindowManager.TRANSIT_CHANGE
+import android.window.TransitionInfo
+import android.window.WindowContainerToken
+import androidx.test.filters.SmallTest
+import androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread
+import com.android.internal.jank.InteractionJankMonitor
+import com.android.wm.shell.ShellTaskOrganizer
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayLayout
+import com.android.wm.shell.transition.Transitions
+import com.android.wm.shell.transition.Transitions.TransitionFinishCallback
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_UNDEFINED
+import java.util.function.Supplier
+import junit.framework.Assert
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.argThat
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+/**
+ * Tests for [MultiDisplayVeiledResizeTaskPositioner].
+ *
+ * Build/Install/Run: atest WMShellUnitTests:MultiDisplayVeiledResizeTaskPositionerTest
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class MultiDisplayVeiledResizeTaskPositionerTest : ShellTestCase() {
+
+ @Mock private lateinit var mockShellTaskOrganizer: ShellTaskOrganizer
+ @Mock private lateinit var mockDesktopWindowDecoration: DesktopModeWindowDecoration
+ @Mock
+ private lateinit var mockDragEventListener: DragPositioningCallbackUtility.DragEventListener
+
+ @Mock private lateinit var taskToken: WindowContainerToken
+ @Mock private lateinit var taskBinder: IBinder
+
+ @Mock private lateinit var mockDisplayController: DisplayController
+ @Mock private lateinit var mockDisplayLayout: DisplayLayout
+ @Mock private lateinit var mockDisplay: Display
+ @Mock private lateinit var mockTransactionFactory: Supplier<SurfaceControl.Transaction>
+ @Mock private lateinit var mockTransaction: SurfaceControl.Transaction
+ @Mock private lateinit var mockTransitionBinder: IBinder
+ @Mock private lateinit var mockTransitionInfo: TransitionInfo
+ @Mock private lateinit var mockFinishCallback: TransitionFinishCallback
+ @Mock private lateinit var mockTransitions: Transitions
+ @Mock private lateinit var mockContext: Context
+ @Mock private lateinit var mockResources: Resources
+ @Mock private lateinit var mockInteractionJankMonitor: InteractionJankMonitor
+ private val mainHandler = Handler(Looper.getMainLooper())
+
+ private lateinit var taskPositioner: MultiDisplayVeiledResizeTaskPositioner
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ mockDesktopWindowDecoration.mDisplay = mockDisplay
+ mockDesktopWindowDecoration.mDecorWindowContext = mockContext
+ whenever(mockContext.getResources()).thenReturn(mockResources)
+ whenever(taskToken.asBinder()).thenReturn(taskBinder)
+ whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
+ whenever(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
+ whenever(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
+ if (
+ mockDesktopWindowDecoration.mTaskInfo.configuration.windowConfiguration
+ .displayRotation == ROTATION_90 ||
+ mockDesktopWindowDecoration.mTaskInfo.configuration.windowConfiguration
+ .displayRotation == ROTATION_270
+ ) {
+ (i.arguments.first() as Rect).set(STABLE_BOUNDS_LANDSCAPE)
+ } else {
+ (i.arguments.first() as Rect).set(STABLE_BOUNDS_PORTRAIT)
+ }
+ }
+ `when`(mockTransactionFactory.get()).thenReturn(mockTransaction)
+ mockDesktopWindowDecoration.mTaskInfo =
+ ActivityManager.RunningTaskInfo().apply {
+ taskId = TASK_ID
+ token = taskToken
+ minWidth = MIN_WIDTH
+ minHeight = MIN_HEIGHT
+ defaultMinSize = DEFAULT_MIN
+ displayId = DISPLAY_ID
+ configuration.windowConfiguration.setBounds(STARTING_BOUNDS)
+ configuration.windowConfiguration.displayRotation = ROTATION_90
+ isResizeable = true
+ }
+ `when`(mockDesktopWindowDecoration.calculateValidDragArea()).thenReturn(VALID_DRAG_AREA)
+ mockDesktopWindowDecoration.mDisplay = mockDisplay
+ whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
+
+ taskPositioner =
+ MultiDisplayVeiledResizeTaskPositioner(
+ mockShellTaskOrganizer,
+ mockDesktopWindowDecoration,
+ mockDisplayController,
+ mockDragEventListener,
+ mockTransactionFactory,
+ mockTransitions,
+ mockInteractionJankMonitor,
+ mainHandler,
+ )
+ }
+
+ @Test
+ fun testDragResize_noMove_doesNotShowResizeVeil() = runOnUiThread {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_TOP or CTRL_TYPE_RIGHT,
+ DISPLAY_ID,
+ STARTING_BOUNDS.left.toFloat(),
+ STARTING_BOUNDS.top.toFloat(),
+ )
+ verify(mockDesktopWindowDecoration, never()).showResizeVeil(STARTING_BOUNDS)
+
+ taskPositioner.onDragPositioningEnd(
+ DISPLAY_ID,
+ STARTING_BOUNDS.left.toFloat(),
+ STARTING_BOUNDS.top.toFloat(),
+ )
+
+ verify(mockTransitions, never())
+ .startTransition(
+ eq(TRANSIT_CHANGE),
+ argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) !=
+ 0 &&
+ change.configuration.windowConfiguration.bounds == STARTING_BOUNDS
+ }
+ },
+ eq(taskPositioner),
+ )
+ verify(mockDesktopWindowDecoration, never()).hideResizeVeil()
+ }
+
+ @Test
+ fun testDragResize_movesTask_doesNotShowResizeVeil() = runOnUiThread {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_UNDEFINED,
+ DISPLAY_ID,
+ STARTING_BOUNDS.left.toFloat(),
+ STARTING_BOUNDS.top.toFloat(),
+ )
+
+ taskPositioner.onDragPositioningMove(
+ DISPLAY_ID,
+ STARTING_BOUNDS.left.toFloat() + 60,
+ STARTING_BOUNDS.top.toFloat() + 100,
+ )
+ val rectAfterMove = Rect(STARTING_BOUNDS)
+ rectAfterMove.left += 60
+ rectAfterMove.right += 60
+ rectAfterMove.top += 100
+ rectAfterMove.bottom += 100
+ verify(mockTransaction)
+ .setPosition(any(), eq(rectAfterMove.left.toFloat()), eq(rectAfterMove.top.toFloat()))
+
+ val endBounds =
+ taskPositioner.onDragPositioningEnd(
+ DISPLAY_ID,
+ STARTING_BOUNDS.left.toFloat() + 70,
+ STARTING_BOUNDS.top.toFloat() + 20,
+ )
+ val rectAfterEnd = Rect(STARTING_BOUNDS)
+ rectAfterEnd.left += 70
+ rectAfterEnd.right += 70
+ rectAfterEnd.top += 20
+ rectAfterEnd.bottom += 20
+
+ verify(mockDesktopWindowDecoration, never()).showResizeVeil(any())
+ verify(mockDesktopWindowDecoration, never()).hideResizeVeil()
+ Assert.assertEquals(rectAfterEnd, endBounds)
+ }
+
+ @Test
+ fun testDragResize_resize_boundsUpdateOnEnd() = runOnUiThread {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
+ DISPLAY_ID,
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat(),
+ )
+
+ taskPositioner.onDragPositioningMove(
+ DISPLAY_ID,
+ STARTING_BOUNDS.right.toFloat() + 10,
+ STARTING_BOUNDS.top.toFloat() + 10,
+ )
+
+ val rectAfterMove = Rect(STARTING_BOUNDS)
+ rectAfterMove.right += 10
+ rectAfterMove.top += 10
+ verify(mockDesktopWindowDecoration).showResizeVeil(rectAfterMove)
+ verify(mockShellTaskOrganizer, never())
+ .applyTransaction(
+ argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) !=
+ 0 &&
+ change.configuration.windowConfiguration.bounds == rectAfterMove
+ }
+ }
+ )
+
+ taskPositioner.onDragPositioningEnd(
+ DISPLAY_ID,
+ STARTING_BOUNDS.right.toFloat() + 20,
+ STARTING_BOUNDS.top.toFloat() + 20,
+ )
+ val rectAfterEnd = Rect(rectAfterMove)
+ rectAfterEnd.right += 10
+ rectAfterEnd.top += 10
+ verify(mockDesktopWindowDecoration).updateResizeVeil(any())
+ verify(mockTransitions)
+ .startTransition(
+ eq(TRANSIT_CHANGE),
+ argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) !=
+ 0 &&
+ change.configuration.windowConfiguration.bounds == rectAfterEnd
+ }
+ },
+ eq(taskPositioner),
+ )
+ }
+
+ @Test
+ fun testDragResize_noEffectiveMove_skipsTransactionOnEnd() = runOnUiThread {
+ taskPositioner.onDragPositioningStart(
+ DISPLAY_ID,
+ CTRL_TYPE_TOP or CTRL_TYPE_RIGHT,
+ STARTING_BOUNDS.left.toFloat(),
+ STARTING_BOUNDS.top.toFloat(),
+ )
+
+ taskPositioner.onDragPositioningMove(
+ DISPLAY_ID,
+ STARTING_BOUNDS.left.toFloat(),
+ STARTING_BOUNDS.top.toFloat(),
+ )
+
+ taskPositioner.onDragPositioningEnd(
+ DISPLAY_ID,
+ STARTING_BOUNDS.left.toFloat() + 10,
+ STARTING_BOUNDS.top.toFloat() + 10,
+ )
+
+ verify(mockTransitions, never())
+ .startTransition(
+ eq(TRANSIT_CHANGE),
+ argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) !=
+ 0 &&
+ change.configuration.windowConfiguration.bounds == STARTING_BOUNDS
+ }
+ },
+ eq(taskPositioner),
+ )
+
+ verify(mockShellTaskOrganizer, never())
+ .applyTransaction(
+ argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) !=
+ 0)
+ }
+ }
+ )
+ }
+
+ @Test
+ fun testDragResize_drag_setBoundsNotRunIfDragEndsInDisallowedEndArea() = runOnUiThread {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_UNDEFINED, // drag
+ DISPLAY_ID,
+ STARTING_BOUNDS.left.toFloat(),
+ STARTING_BOUNDS.top.toFloat(),
+ )
+
+ val newX = STARTING_BOUNDS.left.toFloat() + 5
+ val newY = DISALLOWED_AREA_FOR_END_BOUNDS_HEIGHT.toFloat() - 1
+ taskPositioner.onDragPositioningMove(DISPLAY_ID, newX, newY)
+
+ taskPositioner.onDragPositioningEnd(DISPLAY_ID, newX, newY)
+
+ verify(mockShellTaskOrganizer, never())
+ .applyTransaction(
+ argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) !=
+ 0)
+ }
+ }
+ )
+ }
+
+ @Test
+ fun testDragResize_resize_resizingTaskReorderedToTopWhenNotFocused() = runOnUiThread {
+ mockDesktopWindowDecoration.mHasGlobalFocus = false
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT, // Resize right
+ DISPLAY_ID,
+ STARTING_BOUNDS.left.toFloat(),
+ STARTING_BOUNDS.top.toFloat(),
+ )
+
+ // Verify task is reordered to top
+ verify(mockShellTaskOrganizer)
+ .applyTransaction(
+ argThat { wct ->
+ return@argThat wct.hierarchyOps.any { hierarchyOps ->
+ hierarchyOps.container == taskBinder && hierarchyOps.toTop
+ }
+ }
+ )
+ }
+
+ @Test
+ fun testDragResize_resize_resizingTaskNotReorderedToTopWhenFocused() = runOnUiThread {
+ mockDesktopWindowDecoration.mHasGlobalFocus = true
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT, // Resize right
+ DISPLAY_ID,
+ STARTING_BOUNDS.left.toFloat(),
+ STARTING_BOUNDS.top.toFloat(),
+ )
+
+ // Verify task is not reordered to top
+ verify(mockShellTaskOrganizer, never())
+ .applyTransaction(
+ argThat { wct ->
+ return@argThat wct.hierarchyOps.any { hierarchyOps ->
+ hierarchyOps.container == taskBinder && hierarchyOps.toTop
+ }
+ }
+ )
+ }
+
+ @Test
+ fun testDragResize_drag_draggedTaskNotReorderedToTop() = runOnUiThread {
+ mockDesktopWindowDecoration.mHasGlobalFocus = false
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_UNDEFINED, // drag
+ DISPLAY_ID,
+ STARTING_BOUNDS.left.toFloat(),
+ STARTING_BOUNDS.top.toFloat(),
+ )
+
+ // Verify task is not reordered to top since task is already brought to top before dragging
+ // begins
+ verify(mockShellTaskOrganizer, never())
+ .applyTransaction(
+ argThat { wct ->
+ return@argThat wct.hierarchyOps.any { hierarchyOps ->
+ hierarchyOps.container == taskBinder && hierarchyOps.toTop
+ }
+ }
+ )
+ }
+
+ @Test
+ fun testDragResize_drag_updatesStableBoundsOnRotate() = runOnUiThread {
+ // Test landscape stable bounds
+ performDrag(
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.bottom.toFloat(),
+ STARTING_BOUNDS.right.toFloat() + 2000,
+ STARTING_BOUNDS.bottom.toFloat() + 2000,
+ CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM,
+ )
+ val rectAfterDrag = Rect(STARTING_BOUNDS)
+ rectAfterDrag.right += 2000
+ rectAfterDrag.bottom = STABLE_BOUNDS_LANDSCAPE.bottom
+ // First drag; we should fetch stable bounds.
+ verify(mockDisplayLayout, times(1)).getStableBounds(any())
+ verify(mockTransitions)
+ .startTransition(
+ eq(TRANSIT_CHANGE),
+ argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) !=
+ 0 &&
+ change.configuration.windowConfiguration.bounds == rectAfterDrag
+ }
+ },
+ eq(taskPositioner),
+ )
+ // Drag back to starting bounds.
+ performDrag(
+ STARTING_BOUNDS.right.toFloat() + 2000,
+ STARTING_BOUNDS.bottom.toFloat(),
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.bottom.toFloat(),
+ CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM,
+ )
+
+ // Display did not rotate; we should use previous stable bounds
+ verify(mockDisplayLayout, times(1)).getStableBounds(any())
+
+ // Rotate the screen to portrait
+ mockDesktopWindowDecoration.mTaskInfo.apply {
+ configuration.windowConfiguration.displayRotation = ROTATION_0
+ }
+ // Test portrait stable bounds
+ performDrag(
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.bottom.toFloat(),
+ STARTING_BOUNDS.right.toFloat() + 2000,
+ STARTING_BOUNDS.bottom.toFloat() + 2000,
+ CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM,
+ )
+ rectAfterDrag.right = STABLE_BOUNDS_PORTRAIT.right
+ rectAfterDrag.bottom = STARTING_BOUNDS.bottom + 2000
+
+ verify(mockTransitions)
+ .startTransition(
+ eq(TRANSIT_CHANGE),
+ argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) !=
+ 0 &&
+ change.configuration.windowConfiguration.bounds == rectAfterDrag
+ }
+ },
+ eq(taskPositioner),
+ )
+ // Display has rotated; we expect a new stable bounds.
+ verify(mockDisplayLayout, times(2)).getStableBounds(any())
+ }
+
+ @Test
+ fun testIsResizingOrAnimatingResizeSet() = runOnUiThread {
+ Assert.assertFalse(taskPositioner.isResizingOrAnimating)
+
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_TOP or CTRL_TYPE_RIGHT,
+ DISPLAY_ID,
+ STARTING_BOUNDS.left.toFloat(),
+ STARTING_BOUNDS.top.toFloat(),
+ )
+
+ taskPositioner.onDragPositioningMove(
+ DISPLAY_ID,
+ STARTING_BOUNDS.left.toFloat() - 20,
+ STARTING_BOUNDS.top.toFloat() - 20,
+ )
+
+ // isResizingOrAnimating should be set to true after move during a resize
+ Assert.assertTrue(taskPositioner.isResizingOrAnimating)
+ verify(mockDragEventListener, times(1)).onDragMove(eq(TASK_ID))
+
+ taskPositioner.onDragPositioningEnd(
+ DISPLAY_ID,
+ STARTING_BOUNDS.left.toFloat(),
+ STARTING_BOUNDS.top.toFloat(),
+ )
+
+ // isResizingOrAnimating should be not be set till false until after transition animation
+ Assert.assertTrue(taskPositioner.isResizingOrAnimating)
+ }
+
+ @Test
+ fun testIsResizingOrAnimatingResizeResetAfterStartAnimation() = runOnUiThread {
+ performDrag(
+ STARTING_BOUNDS.left.toFloat(),
+ STARTING_BOUNDS.top.toFloat(),
+ STARTING_BOUNDS.left.toFloat() - 20,
+ STARTING_BOUNDS.top.toFloat() - 20,
+ CTRL_TYPE_TOP or CTRL_TYPE_RIGHT,
+ )
+
+ taskPositioner.startAnimation(
+ mockTransitionBinder,
+ mockTransitionInfo,
+ mockTransaction,
+ mockTransaction,
+ mockFinishCallback,
+ )
+
+ // isResizingOrAnimating should be set to false until after transition successfully consumed
+ Assert.assertFalse(taskPositioner.isResizingOrAnimating)
+ }
+
+ @Test
+ fun testStartAnimation_useEndRelOffset() = runOnUiThread {
+ val changeMock = mock(TransitionInfo.Change::class.java)
+ val startTransaction = mock(Transaction::class.java)
+ val finishTransaction = mock(Transaction::class.java)
+ val point = Point(10, 20)
+ val bounds = Rect(1, 2, 3, 4)
+ `when`(changeMock.leash).thenReturn(mock(SurfaceControl::class.java))
+ `when`(changeMock.endRelOffset).thenReturn(point)
+ `when`(changeMock.endAbsBounds).thenReturn(bounds)
+ `when`(mockTransitionInfo.changes).thenReturn(listOf(changeMock))
+ `when`(startTransaction.setWindowCrop(any(), eq(bounds.width()), eq(bounds.height())))
+ .thenReturn(startTransaction)
+ `when`(finishTransaction.setWindowCrop(any(), eq(bounds.width()), eq(bounds.height())))
+ .thenReturn(finishTransaction)
+
+ taskPositioner.startAnimation(
+ mockTransitionBinder,
+ mockTransitionInfo,
+ startTransaction,
+ finishTransaction,
+ mockFinishCallback,
+ )
+
+ verify(startTransaction).setPosition(any(), eq(point.x.toFloat()), eq(point.y.toFloat()))
+ verify(finishTransaction).setPosition(any(), eq(point.x.toFloat()), eq(point.y.toFloat()))
+ verify(changeMock).endRelOffset
+ }
+
+ private fun performDrag(startX: Float, startY: Float, endX: Float, endY: Float, ctrlType: Int) {
+ taskPositioner.onDragPositioningStart(ctrlType, DISPLAY_ID, startX, startY)
+ taskPositioner.onDragPositioningMove(DISPLAY_ID, endX, endY)
+
+ taskPositioner.onDragPositioningEnd(DISPLAY_ID, endX, endY)
+ }
+
+ companion object {
+ private const val TASK_ID = 5
+ private const val MIN_WIDTH = 10
+ private const val MIN_HEIGHT = 10
+ private const val DENSITY_DPI = 20
+ private const val DEFAULT_MIN = 40
+ private const val DISPLAY_ID = 1
+ private const val NAVBAR_HEIGHT = 50
+ private const val CAPTION_HEIGHT = 50
+ private const val DISALLOWED_AREA_FOR_END_BOUNDS_HEIGHT = 10
+ private val DISPLAY_BOUNDS = Rect(0, 0, 2400, 1600)
+ private val STARTING_BOUNDS = Rect(100, 100, 200, 200)
+ private val STABLE_BOUNDS_LANDSCAPE =
+ Rect(
+ DISPLAY_BOUNDS.left,
+ DISPLAY_BOUNDS.top + CAPTION_HEIGHT,
+ DISPLAY_BOUNDS.right,
+ DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT,
+ )
+ private val STABLE_BOUNDS_PORTRAIT =
+ Rect(
+ DISPLAY_BOUNDS.top,
+ DISPLAY_BOUNDS.left + CAPTION_HEIGHT,
+ DISPLAY_BOUNDS.bottom,
+ DISPLAY_BOUNDS.right - NAVBAR_HEIGHT,
+ )
+ private val VALID_DRAG_AREA =
+ Rect(
+ DISPLAY_BOUNDS.left - 100,
+ STABLE_BOUNDS_LANDSCAPE.top,
+ DISPLAY_BOUNDS.right - 100,
+ DISPLAY_BOUNDS.bottom - 100,
+ )
+ }
+}
diff --git a/libs/androidfw/ApkParsing.cpp b/libs/androidfw/ApkParsing.cpp
index 7eedfdb5c921..b80c8755f23e 100644
--- a/libs/androidfw/ApkParsing.cpp
+++ b/libs/androidfw/ApkParsing.cpp
@@ -33,7 +33,7 @@ const size_t LIB_SUFFIX_LEN = LIB_SUFFIX.size();
static const std::array<std::string_view, 2> abis = {"arm64-v8a", "x86_64"};
namespace android::util {
-const char* ValidLibraryPathLastSlash(const char* fileName, bool suppress64Bit, bool debuggable) {
+const char* ValidLibraryPathLastSlash(const char* fileName, bool suppress64Bit) {
// Make sure the filename is at least to the minimum library name size.
const size_t fileNameLen = strlen(fileName);
static const size_t minLength = APK_LIB_LEN + 2 + LIB_PREFIX_LEN + 1 + LIB_SUFFIX_LEN;
@@ -66,14 +66,6 @@ const char* ValidLibraryPathLastSlash(const char* fileName, bool suppress64Bit,
return nullptr;
}
- if (!debuggable) {
- // Make sure the filename starts with lib and ends with ".so".
- if (strncmp(fileName + fileNameLen - LIB_SUFFIX_LEN, LIB_SUFFIX.data(), LIB_SUFFIX_LEN) != 0
- || strncmp(lastSlash, LIB_PREFIX.data(), LIB_PREFIX_LEN) != 0) {
- return nullptr;
- }
- }
-
// Don't include 64 bit versions if they are suppressed
if (suppress64Bit && std::find(abis.begin(), abis.end(), std::string_view(
fileName + APK_LIB_LEN, lastSlash - fileName - APK_LIB_LEN)) != abis.end()) {
diff --git a/libs/androidfw/include/androidfw/ApkParsing.h b/libs/androidfw/include/androidfw/ApkParsing.h
index 194eaae8e12a..b288e152f383 100644
--- a/libs/androidfw/include/androidfw/ApkParsing.h
+++ b/libs/androidfw/include/androidfw/ApkParsing.h
@@ -24,7 +24,7 @@ extern const size_t APK_LIB_LEN;
namespace android::util {
// Checks if filename is a valid library path and returns a pointer to the last slash in the path
// if it is, nullptr otherwise
-const char* ValidLibraryPathLastSlash(const char* filename, bool suppress64Bit, bool debuggable);
+const char* ValidLibraryPathLastSlash(const char* filename, bool suppress64Bit);
// Equivalent to android.os.FileUtils.isFilenameSafe
bool isFilenameSafe(const char* filename);
diff --git a/libs/androidfw/tests/ApkParsing_test.cpp b/libs/androidfw/tests/ApkParsing_test.cpp
index ac1dc9b88463..f1f9d7166914 100644
--- a/libs/androidfw/tests/ApkParsing_test.cpp
+++ b/libs/androidfw/tests/ApkParsing_test.cpp
@@ -27,57 +27,45 @@ using ::testing::NotNull;
namespace android {
TEST(ApkParsingTest, ValidArm64Path) {
const char* path = "lib/arm64-v8a/library.so";
- auto lastSlash = util::ValidLibraryPathLastSlash(path, false, false);
+ auto lastSlash = util::ValidLibraryPathLastSlash(path, false);
ASSERT_THAT(lastSlash, NotNull());
ASSERT_THAT(lastSlash, Eq(path + 13));
}
TEST(ApkParsingTest, ValidArm64PathButSuppressed) {
const char* path = "lib/arm64-v8a/library.so";
- auto lastSlash = util::ValidLibraryPathLastSlash(path, true, false);
+ auto lastSlash = util::ValidLibraryPathLastSlash(path, true);
ASSERT_THAT(lastSlash, IsNull());
}
TEST(ApkParsingTest, ValidArm32Path) {
const char* path = "lib/armeabi-v7a/library.so";
- auto lastSlash = util::ValidLibraryPathLastSlash(path, false, false);
+ auto lastSlash = util::ValidLibraryPathLastSlash(path, false);
ASSERT_THAT(lastSlash, NotNull());
ASSERT_THAT(lastSlash, Eq(path + 15));
}
-TEST(ApkParsingTest, InvalidMustStartWithLib) {
- const char* path = "lib/arm64-v8a/random.so";
- auto lastSlash = util::ValidLibraryPathLastSlash(path, false, false);
- ASSERT_THAT(lastSlash, IsNull());
-}
-
-TEST(ApkParsingTest, InvalidMustEndInSo) {
- const char* path = "lib/arm64-v8a/library.txt";
- auto lastSlash = util::ValidLibraryPathLastSlash(path, false, false);
- ASSERT_THAT(lastSlash, IsNull());
-}
-
TEST(ApkParsingTest, InvalidCharacter) {
const char* path = "lib/arm64-v8a/lib#.so";
- auto lastSlash = util::ValidLibraryPathLastSlash(path, false, false);
+ auto lastSlash = util::ValidLibraryPathLastSlash(path, false);
ASSERT_THAT(lastSlash, IsNull());
}
TEST(ApkParsingTest, InvalidSubdirectories) {
const char* path = "lib/arm64-v8a/anything/library.so";
- auto lastSlash = util::ValidLibraryPathLastSlash(path, false, false);
+ auto lastSlash = util::ValidLibraryPathLastSlash(path, false);
ASSERT_THAT(lastSlash, IsNull());
}
TEST(ApkParsingTest, InvalidFileAtRoot) {
const char* path = "lib/library.so";
- auto lastSlash = util::ValidLibraryPathLastSlash(path, false, false);
+ auto lastSlash = util::ValidLibraryPathLastSlash(path, false);
ASSERT_THAT(lastSlash, IsNull());
}
TEST(ApkParsingTest, InvalidPrefix) {
const char* path = "assets/libhello.so";
- auto lastSlash = util::ValidLibraryPathLastSlash(path, false, false);
+ auto lastSlash = util::ValidLibraryPathLastSlash(path, false);
ASSERT_THAT(lastSlash, IsNull());
}
} \ No newline at end of file
diff --git a/libs/hwui/aconfig/hwui_flags.aconfig b/libs/hwui/aconfig/hwui_flags.aconfig
index 5e71d3360f39..2851dd8b1003 100644
--- a/libs/hwui/aconfig/hwui_flags.aconfig
+++ b/libs/hwui/aconfig/hwui_flags.aconfig
@@ -42,6 +42,16 @@ flag {
}
flag {
+ name: "high_contrast_text_inner_text_color"
+ namespace: "accessibility"
+ description: "Render text color by modifying its brightness instead of defaulting to black and white"
+ bug: "384793956"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "hdr_10bit_plus"
namespace: "core_graphics"
description: "Use 10101010 and FP16 formats for HDR-UI when available"
diff --git a/libs/hwui/hwui/DrawTextFunctor.h b/libs/hwui/hwui/DrawTextFunctor.h
index e05c3d695463..008b693edf02 100644
--- a/libs/hwui/hwui/DrawTextFunctor.h
+++ b/libs/hwui/hwui/DrawTextFunctor.h
@@ -37,6 +37,9 @@ namespace flags {
constexpr bool high_contrast_text_small_text_rect() {
return false;
}
+constexpr bool high_contrast_text_inner_text_color() {
+ return false;
+}
} // namespace flags
#endif
@@ -126,7 +129,25 @@ public:
// inner
gDrawTextBlobMode = DrawTextBlobMode::HctInner;
Paint innerPaint(paint);
- simplifyPaint(darken ? SK_ColorBLACK : SK_ColorWHITE, &innerPaint);
+ if (flags::high_contrast_text_inner_text_color()) {
+ // Preserve some color information while still ensuring sufficient contrast.
+ // Thus we increase the lightness to make the color stand out against a black
+ // background, and vice-versa. For grayscale, we retain some gray to indicate
+ // states like disabled or to distinguish links.
+ bool isGrayscale = abs(lab.a) < 1 && abs(lab.b) < 1;
+ if (isGrayscale) {
+ if (darken) {
+ lab.L = lab.L < 40 ? 0 : 20;
+ } else {
+ lab.L = lab.L > 60 ? 100 : 80;
+ }
+ } else {
+ lab.L = darken ? 20 : 90;
+ }
+ simplifyPaint(uirenderer::LabToSRGB(lab, SK_AlphaOPAQUE), &innerPaint);
+ } else {
+ simplifyPaint(darken ? SK_ColorBLACK : SK_ColorWHITE, &innerPaint);
+ }
innerPaint.setStyle(SkPaint::kFill_Style);
canvas->drawGlyphs(glyphFunc, glyphCount, innerPaint, x, y, totalAdvance);
gDrawTextBlobMode = DrawTextBlobMode::Normal;
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 69fe40c755ea..6ab8e4e0e2ab 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -323,6 +323,7 @@ void RenderThread::initGrContextOptions(GrContextOptions& options) {
}
void RenderThread::destroyRenderingContext() {
+ ATRACE_CALL();
mFunctorManager.onContextDestroyed();
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
if (mEglManager->hasEglContext()) {
@@ -520,7 +521,10 @@ void RenderThread::preload() {
// EGL driver is always preloaded only if HWUI renders with GL.
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
if (Properties::earlyPreloadGlContext()) {
- queue().post([this]() { requireGlContext(); });
+ queue().post([this]() {
+ ATRACE_NAME("earlyPreloadGlContext");
+ requireGlContext();
+ });
} else {
std::thread eglInitThread([]() { eglGetDisplay(EGL_DEFAULT_DISPLAY); });
eglInitThread.detach();
@@ -528,9 +532,6 @@ void RenderThread::preload() {
} else {
requireVkContext();
}
- if (Properties::earlyPreloadGlContext()) {
- queue().post([]() { GraphicBufferAllocator::getInstance(); });
- }
HardwareBitmapUploader::initialize();
}
diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java
index cdde7c66e268..9746dab4151c 100644
--- a/location/java/android/location/Geocoder.java
+++ b/location/java/android/location/Geocoder.java
@@ -83,8 +83,11 @@ public final class Geocoder {
* succeed.
*/
public static boolean isPresent() {
- ILocationManager lm = Objects.requireNonNull(ILocationManager.Stub.asInterface(
- ServiceManager.getService(Context.LOCATION_SERVICE)));
+ ILocationManager lm = ILocationManager.Stub.asInterface(
+ ServiceManager.getService(Context.LOCATION_SERVICE));
+ if (lm == null) {
+ return false;
+ }
try {
return lm.isGeocodeAvailable();
} catch (RemoteException e) {
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index f42017dc835a..3104f9d42891 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -503,7 +503,10 @@ public abstract class MediaRoute2ProviderService extends Service {
String sessionId = sessionInfo.getId();
synchronized (mSessionLock) {
- if (mSessionInfos.containsKey(sessionId)) {
+ var mediaStreams = mOngoingMediaStreams.get(sessionId);
+ if (Flags.enableMirroringInMediaRouter2() && mediaStreams != null) {
+ mediaStreams.mSessionInfo = sessionInfo;
+ } else if (mSessionInfos.containsKey(sessionId)) {
mSessionInfos.put(sessionId, sessionInfo);
} else {
Log.w(TAG, "notifySessionUpdated: Ignoring unknown session info.");
@@ -836,6 +839,9 @@ public abstract class MediaRoute2ProviderService extends Service {
List<RoutingSessionInfo> sessions;
synchronized (mSessionLock) {
sessions = new ArrayList<>(mSessionInfos.values());
+ if (Flags.enableMirroringInMediaRouter2()) {
+ mOngoingMediaStreams.values().forEach(it -> sessions.add(it.mSessionInfo));
+ }
}
try {
@@ -888,7 +894,13 @@ public abstract class MediaRoute2ProviderService extends Service {
Log.w(TAG, description + ": Ignoring empty sessionId from system service.");
return false;
}
- if (getSessionInfo(sessionId) == null) {
+ boolean idMatchesSystemSession = false;
+ if (Flags.enableMirroringInMediaRouter2()) {
+ synchronized (mSessionLock) {
+ idMatchesSystemSession = mOngoingMediaStreams.containsKey(sessionId);
+ }
+ }
+ if (!idMatchesSystemSession && getSessionInfo(sessionId) == null) {
Log.w(TAG, description + ": Ignoring unknown session from system service. "
+ "sessionId=" + sessionId);
return false;
@@ -1079,8 +1091,8 @@ public abstract class MediaRoute2ProviderService extends Service {
*
* @hide
*/
- @GuardedBy("MediaRoute2ProviderService.this.mSessionLock")
@NonNull
+ // Access guarded by mSessionsLock, but it's not convenient to enforce through @GuardedBy.
private RoutingSessionInfo mSessionInfo;
// TODO: b/380431086: Add the video equivalent.
diff --git a/media/java/android/media/quality/MediaQualityManager.java b/media/java/android/media/quality/MediaQualityManager.java
index 191b938b2e26..b7269256a449 100644
--- a/media/java/android/media/quality/MediaQualityManager.java
+++ b/media/java/android/media/quality/MediaQualityManager.java
@@ -18,6 +18,7 @@ package android.media.quality;
import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -35,6 +36,8 @@ import androidx.annotation.RequiresPermission;
import com.android.internal.util.Preconditions;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -54,14 +57,17 @@ public final class MediaQualityManager {
private final IMediaQualityManager mService;
private final Context mContext;
private final UserHandle mUserHandle;
- private final Object mLock = new Object();
- // @GuardedBy("mLock")
+ private final Object mPpLock = new Object();
+ private final Object mSpLock = new Object();
+ private final Object mAbLock = new Object();
+ private final Object mApLock = new Object();
+ // @GuardedBy("mPpLock")
private final List<PictureProfileCallbackRecord> mPpCallbackRecords = new ArrayList<>();
- // @GuardedBy("mLock")
+ // @GuardedBy("mSpLock")
private final List<SoundProfileCallbackRecord> mSpCallbackRecords = new ArrayList<>();
- // @GuardedBy("mLock")
+ // @GuardedBy("mAbLock")
private final List<AmbientBacklightCallbackRecord> mAbCallbackRecords = new ArrayList<>();
- // @GuardedBy("mLock")
+ // @GuardedBy("mApLock")
private final List<ActiveProcessingPictureListenerRecord> mApListenerRecords =
new ArrayList<>();
@@ -71,6 +77,39 @@ public final class MediaQualityManager {
*/
public static final String OPTION_INCLUDE_PARAMETERS = "include_parameters";
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({AMBIENT_BACKLIGHT_EVENT_ENABLED, AMBIENT_BACKLIGHT_EVENT_DISABLED,
+ AMBIENT_BACKLIGHT_EVENT_METADATA,
+ AMBIENT_BACKLIGHT_EVENT_INTERRUPTED})
+ public @interface AmbientBacklightEventTypes {}
+
+ /**
+ * Event type for ambient backlight events. The ambient backlight is enabled.
+ * @hide
+ */
+ public static final int AMBIENT_BACKLIGHT_EVENT_ENABLED = 1;
+
+ /**
+ * Event type for ambient backlight events. The ambient backlight is disabled.
+ * @hide
+ */
+ public static final int AMBIENT_BACKLIGHT_EVENT_DISABLED = 2;
+
+ /**
+ * Event type for ambient backlight events. The ambient backlight metadata is
+ * available.
+ * @hide
+ */
+ public static final int AMBIENT_BACKLIGHT_EVENT_METADATA = 3;
+
+ /**
+ * Event type for ambient backlight events. The ambient backlight event is
+ * preempted by another application.
+ * @hide
+ */
+ public static final int AMBIENT_BACKLIGHT_EVENT_INTERRUPTED = 4;
+
/**
* @hide
@@ -82,7 +121,7 @@ public final class MediaQualityManager {
IPictureProfileCallback ppCallback = new IPictureProfileCallback.Stub() {
@Override
public void onPictureProfileAdded(String profileId, PictureProfile profile) {
- synchronized (mLock) {
+ synchronized (mPpLock) {
for (PictureProfileCallbackRecord record : mPpCallbackRecords) {
// TODO: filter callback record
record.postPictureProfileAdded(profileId, profile);
@@ -91,7 +130,7 @@ public final class MediaQualityManager {
}
@Override
public void onPictureProfileUpdated(String profileId, PictureProfile profile) {
- synchronized (mLock) {
+ synchronized (mPpLock) {
for (PictureProfileCallbackRecord record : mPpCallbackRecords) {
// TODO: filter callback record
record.postPictureProfileUpdated(profileId, profile);
@@ -100,7 +139,7 @@ public final class MediaQualityManager {
}
@Override
public void onPictureProfileRemoved(String profileId, PictureProfile profile) {
- synchronized (mLock) {
+ synchronized (mPpLock) {
for (PictureProfileCallbackRecord record : mPpCallbackRecords) {
// TODO: filter callback record
record.postPictureProfileRemoved(profileId, profile);
@@ -110,7 +149,7 @@ public final class MediaQualityManager {
@Override
public void onParameterCapabilitiesChanged(
String profileId, List<ParameterCapability> caps) {
- synchronized (mLock) {
+ synchronized (mPpLock) {
for (PictureProfileCallbackRecord record : mPpCallbackRecords) {
// TODO: filter callback record
record.postParameterCapabilitiesChanged(profileId, caps);
@@ -119,7 +158,7 @@ public final class MediaQualityManager {
}
@Override
public void onError(String profileId, int err) {
- synchronized (mLock) {
+ synchronized (mPpLock) {
for (PictureProfileCallbackRecord record : mPpCallbackRecords) {
// TODO: filter callback record
record.postError(profileId, err);
@@ -130,7 +169,7 @@ public final class MediaQualityManager {
ISoundProfileCallback spCallback = new ISoundProfileCallback.Stub() {
@Override
public void onSoundProfileAdded(String profileId, SoundProfile profile) {
- synchronized (mLock) {
+ synchronized (mSpLock) {
for (SoundProfileCallbackRecord record : mSpCallbackRecords) {
// TODO: filter callback record
record.postSoundProfileAdded(profileId, profile);
@@ -139,7 +178,7 @@ public final class MediaQualityManager {
}
@Override
public void onSoundProfileUpdated(String profileId, SoundProfile profile) {
- synchronized (mLock) {
+ synchronized (mSpLock) {
for (SoundProfileCallbackRecord record : mSpCallbackRecords) {
// TODO: filter callback record
record.postSoundProfileUpdated(profileId, profile);
@@ -148,7 +187,7 @@ public final class MediaQualityManager {
}
@Override
public void onSoundProfileRemoved(String profileId, SoundProfile profile) {
- synchronized (mLock) {
+ synchronized (mSpLock) {
for (SoundProfileCallbackRecord record : mSpCallbackRecords) {
// TODO: filter callback record
record.postSoundProfileRemoved(profileId, profile);
@@ -158,7 +197,7 @@ public final class MediaQualityManager {
@Override
public void onParameterCapabilitiesChanged(
String profileId, List<ParameterCapability> caps) {
- synchronized (mLock) {
+ synchronized (mSpLock) {
for (SoundProfileCallbackRecord record : mSpCallbackRecords) {
// TODO: filter callback record
record.postParameterCapabilitiesChanged(profileId, caps);
@@ -167,7 +206,7 @@ public final class MediaQualityManager {
}
@Override
public void onError(String profileId, int err) {
- synchronized (mLock) {
+ synchronized (mSpLock) {
for (SoundProfileCallbackRecord record : mSpCallbackRecords) {
// TODO: filter callback record
record.postError(profileId, err);
@@ -178,7 +217,7 @@ public final class MediaQualityManager {
IAmbientBacklightCallback abCallback = new IAmbientBacklightCallback.Stub() {
@Override
public void onAmbientBacklightEvent(AmbientBacklightEvent event) {
- synchronized (mLock) {
+ synchronized (mAbLock) {
for (AmbientBacklightCallbackRecord record : mAbCallbackRecords) {
record.postAmbientBacklightEvent(event);
}
@@ -205,7 +244,7 @@ public final class MediaQualityManager {
@NonNull PictureProfileCallback callback) {
Preconditions.checkNotNull(callback);
Preconditions.checkNotNull(executor);
- synchronized (mLock) {
+ synchronized (mPpLock) {
mPpCallbackRecords.add(new PictureProfileCallbackRecord(callback, executor));
}
}
@@ -215,7 +254,7 @@ public final class MediaQualityManager {
*/
public void unregisterPictureProfileCallback(@NonNull final PictureProfileCallback callback) {
Preconditions.checkNotNull(callback);
- synchronized (mLock) {
+ synchronized (mPpLock) {
for (Iterator<PictureProfileCallbackRecord> it = mPpCallbackRecords.iterator();
it.hasNext(); ) {
PictureProfileCallbackRecord record = it.next();
@@ -416,7 +455,7 @@ public final class MediaQualityManager {
@NonNull SoundProfileCallback callback) {
Preconditions.checkNotNull(callback);
Preconditions.checkNotNull(executor);
- synchronized (mLock) {
+ synchronized (mSpLock) {
mSpCallbackRecords.add(new SoundProfileCallbackRecord(callback, executor));
}
}
@@ -426,7 +465,7 @@ public final class MediaQualityManager {
*/
public void unregisterSoundProfileCallback(@NonNull final SoundProfileCallback callback) {
Preconditions.checkNotNull(callback);
- synchronized (mLock) {
+ synchronized (mSpLock) {
for (Iterator<SoundProfileCallbackRecord> it = mSpCallbackRecords.iterator();
it.hasNext(); ) {
SoundProfileCallbackRecord record = it.next();
@@ -785,7 +824,7 @@ public final class MediaQualityManager {
@NonNull AmbientBacklightCallback callback) {
Preconditions.checkNotNull(callback);
Preconditions.checkNotNull(executor);
- synchronized (mLock) {
+ synchronized (mAbLock) {
mAbCallbackRecords.add(new AmbientBacklightCallbackRecord(callback, executor));
}
}
@@ -797,7 +836,7 @@ public final class MediaQualityManager {
public void unregisterAmbientBacklightCallback(
@NonNull final AmbientBacklightCallback callback) {
Preconditions.checkNotNull(callback);
- synchronized (mLock) {
+ synchronized (mAbLock) {
for (Iterator<AmbientBacklightCallbackRecord> it = mAbCallbackRecords.iterator();
it.hasNext(); ) {
AmbientBacklightCallbackRecord record = it.next();
@@ -1128,7 +1167,7 @@ public final class MediaQualityManager {
@NonNull Consumer<List<ActiveProcessingPicture>> listener) {
Preconditions.checkNotNull(listener);
Preconditions.checkNotNull(executor);
- synchronized (mLock) {
+ synchronized (mApLock) {
mApListenerRecords.add(
new ActiveProcessingPictureListenerRecord(listener, executor, false));
}
@@ -1147,7 +1186,7 @@ public final class MediaQualityManager {
@NonNull Consumer<List<ActiveProcessingPicture>> listener) {
Preconditions.checkNotNull(listener);
Preconditions.checkNotNull(executor);
- synchronized (mLock) {
+ synchronized (mApLock) {
mApListenerRecords.add(
new ActiveProcessingPictureListenerRecord(listener, executor, true));
}
@@ -1160,7 +1199,7 @@ public final class MediaQualityManager {
public void removeActiveProcessingPictureListener(
@NonNull Consumer<List<ActiveProcessingPicture>> listener) {
Preconditions.checkNotNull(listener);
- synchronized (mLock) {
+ synchronized (mApLock) {
for (Iterator<ActiveProcessingPictureListenerRecord> it = mApListenerRecords.iterator();
it.hasNext(); ) {
ActiveProcessingPictureListenerRecord record = it.next();
diff --git a/media/java/android/media/tv/flags/media_tv.aconfig b/media/java/android/media/tv/flags/media_tv.aconfig
index 3451dfc559ee..28da55656177 100644
--- a/media/java/android/media/tv/flags/media_tv.aconfig
+++ b/media/java/android/media/tv/flags/media_tv.aconfig
@@ -120,3 +120,13 @@ flag {
description: "Collect physical address from HDMI-CEC messages in metrics"
bug: "376001043"
}
+
+flag {
+ name: "tif_extension_standardization_bugfix"
+ namespace: "tv_os"
+ description: "Bug fix flag for standardizing AIDL extension interface of TIS"
+ bug: "389779152"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+} \ No newline at end of file
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 2fe069af638a..bf330dab266c 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -701,6 +701,9 @@ void FilterClientCallbackImpl::getMediaEvent(const jobjectArray& arr, const int
// Protect mFilterClient from being set to null.
android::Mutex::Autolock autoLock(mLock);
+ if (mFilterClient == nullptr) {
+ return;
+ }
uint64_t avSharedMemSize = mFilterClient->getAvSharedHandleInfo().size;
if (mediaEvent.avMemory.fds.size() > 0 || mediaEvent.avDataId != 0 ||
(dataLength > 0 && (dataLength + offset) < avSharedMemSize)) {
@@ -868,10 +871,18 @@ void FilterClientCallbackImpl::getRestartEvent(const jobjectArray& arr, const in
void FilterClientCallbackImpl::onFilterEvent(const vector<DemuxFilterEvent> &events) {
ALOGV("FilterClientCallbackImpl::onFilterEvent");
JNIEnv *env = AndroidRuntime::getJNIEnv();
+
ScopedLocalRef<jobjectArray> array(env);
if (!events.empty()) {
array.reset(env->NewObjectArray(events.size(), mEventClass, nullptr));
+ if (env->IsSameObject(array.get(), nullptr)) {
+ // It can happen when FilterClientCallbackImpl release the resource
+ // in another thread.
+ ALOGE("FilterClientCallbackImpl::onFilterEvent:"
+ "Unable to create object array of filter events. Ignoring callback.");
+ return;
+ }
}
for (int i = 0, arraySize = 0; i < events.size(); i++) {
@@ -1070,14 +1081,15 @@ FilterClientCallbackImpl::FilterClientCallbackImpl() {
FilterClientCallbackImpl::~FilterClientCallbackImpl() {
JNIEnv *env = AndroidRuntime::getJNIEnv();
- {
- android::Mutex::Autolock autoLock(mLock);
- if (mFilterObj != nullptr) {
- env->DeleteWeakGlobalRef(mFilterObj);
- mFilterObj = nullptr;
- }
- mFilterClient = nullptr;
+
+ android::Mutex::Autolock autoLock(mLock);
+
+ if (mFilterObj != nullptr) {
+ env->DeleteWeakGlobalRef(mFilterObj);
+ mFilterObj = nullptr;
}
+ mFilterClient = nullptr;
+
env->DeleteGlobalRef(mEventClass);
env->DeleteGlobalRef(mSectionEventClass);
env->DeleteGlobalRef(mMediaEventClass);
diff --git a/media/tests/MediaRouter/Android.bp b/media/tests/MediaRouter/Android.bp
index e4f88a65ed1a..e63c59d53f2a 100644
--- a/media/tests/MediaRouter/Android.bp
+++ b/media/tests/MediaRouter/Android.bp
@@ -9,7 +9,7 @@ package {
android_test {
name: "mediaroutertest",
- team: "trendy_team_android_media_solutions",
+ team: "trendy_team_android_media_better_together",
srcs: ["**/*.java"],
diff --git a/native/android/TEST_MAPPING b/native/android/TEST_MAPPING
index be84574e6a2c..456c719effc0 100644
--- a/native/android/TEST_MAPPING
+++ b/native/android/TEST_MAPPING
@@ -16,9 +16,7 @@
{
"name": "CtsOsTestCases_cts_performancehintmanagertest",
"file_patterns": ["performance_hint.cpp"]
- }
- ],
- "postsubmit": [
+ },
{
"name": "CtsThermalTestCases",
"file_patterns": ["thermal.cpp"]
@@ -27,5 +25,19 @@
"name": "NativeThermalUnitTestCases",
"file_patterns": ["thermal.cpp"]
}
+ ],
+ "postsubmit": [
+ {
+ "file_patterns": ["system_health.cpp"],
+ "name": "NativeSystemHealthUnitTestCases"
+ },
+ {
+ "file_patterns": ["system_health.cpp"],
+ "name": "CtsSystemHealthTestCases",
+ "options": [
+ {"exclude-annotation": "androidx.test.filters.FlakyTest"},
+ {"exclude-annotation": "org.junit.Ignore"}
+ ]
+ }
]
}
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index b30b779b57b5..49cbd7181d77 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -421,6 +421,7 @@ LIBANDROID {
LIBANDROID_PLATFORM {
global:
AThermal_setIThermalServiceForTesting;
+ ASystemHealth_setIHintManagerForTesting;
APerformanceHint_setIHintManagerForTesting;
APerformanceHint_sendHint;
APerformanceHint_getThreadIds;
diff --git a/native/android/system_health.cpp b/native/android/system_health.cpp
index 5c07ac7bfccc..1b43e71c7bf0 100644
--- a/native/android/system_health.cpp
+++ b/native/android/system_health.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "system_health"
+
#include <aidl/android/hardware/power/CpuHeadroomParams.h>
#include <aidl/android/hardware/power/GpuHeadroomParams.h>
#include <aidl/android/os/CpuHeadroomParamsInternal.h>
@@ -23,6 +25,17 @@
#include <android/system_health.h>
#include <binder/IServiceManager.h>
#include <binder/Status.h>
+#include <system_health_private.h>
+
+#include <list>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <utility>
+
+#include "android-base/thread_annotations.h"
+#include "utils/SystemClock.h"
using namespace android;
using namespace aidl::android::os;
@@ -55,9 +68,20 @@ private:
IHintManager::HintManagerClientData mClientData;
};
+static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
+static std::shared_ptr<ASystemHealthManager> gSystemHealthManagerForTesting = nullptr;
+
ASystemHealthManager* ASystemHealthManager::getInstance() {
static std::once_flag creationFlag;
static ASystemHealthManager* instance = nullptr;
+ if (gSystemHealthManagerForTesting) {
+ return gSystemHealthManagerForTesting.get();
+ }
+ if (gIHintManagerForTesting) {
+ gSystemHealthManagerForTesting =
+ std::shared_ptr<ASystemHealthManager>(create(*gIHintManagerForTesting));
+ return gSystemHealthManagerForTesting.get();
+ }
std::call_once(creationFlag, []() { instance = create(nullptr); });
return instance;
}
@@ -121,7 +145,8 @@ int ASystemHealthManager::getCpuHeadroom(const ACpuHeadroomParams* params, float
}
return EPIPE;
}
- *outHeadroom = res->get<hal::CpuHeadroomResult::Tag::globalHeadroom>();
+ *outHeadroom = res ? res->get<hal::CpuHeadroomResult::Tag::globalHeadroom>()
+ : std::numeric_limits<float>::quiet_NaN();
return OK;
}
@@ -155,37 +180,20 @@ int ASystemHealthManager::getGpuHeadroom(const AGpuHeadroomParams* params, float
}
return EPIPE;
}
- *outHeadroom = res->get<hal::GpuHeadroomResult::Tag::globalHeadroom>();
+ *outHeadroom = res ? res->get<hal::GpuHeadroomResult::Tag::globalHeadroom>()
+ : std::numeric_limits<float>::quiet_NaN();
return OK;
}
int ASystemHealthManager::getCpuHeadroomMinIntervalMillis(int64_t* outMinIntervalMillis) {
if (!mClientData.supportInfo.headroom.isCpuSupported) return ENOTSUP;
- int64_t minIntervalMillis = 0;
- ::ndk::ScopedAStatus ret = mHintManager->getCpuHeadroomMinIntervalMillis(&minIntervalMillis);
- if (!ret.isOk()) {
- ALOGE("ASystemHealth_getCpuHeadroomMinIntervalMillis fails: %s", ret.getMessage());
- if (ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
- return ENOTSUP;
- }
- return EPIPE;
- }
- *outMinIntervalMillis = minIntervalMillis;
+ *outMinIntervalMillis = mClientData.supportInfo.headroom.cpuMinIntervalMillis;
return OK;
}
int ASystemHealthManager::getGpuHeadroomMinIntervalMillis(int64_t* outMinIntervalMillis) {
if (!mClientData.supportInfo.headroom.isGpuSupported) return ENOTSUP;
- int64_t minIntervalMillis = 0;
- ::ndk::ScopedAStatus ret = mHintManager->getGpuHeadroomMinIntervalMillis(&minIntervalMillis);
- if (!ret.isOk()) {
- ALOGE("ASystemHealth_getGpuHeadroomMinIntervalMillis fails: %s", ret.getMessage());
- if (ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
- return ENOTSUP;
- }
- return EPIPE;
- }
- *outMinIntervalMillis = minIntervalMillis;
+ *outMinIntervalMillis = mClientData.supportInfo.headroom.gpuMinIntervalMillis;
return OK;
}
@@ -298,7 +306,6 @@ void ACpuHeadroomParams_setTids(ACpuHeadroomParams* _Nonnull params, const int*
size_t tidsSize) {
LOG_ALWAYS_FATAL_IF(tids == nullptr, "%s: tids should not be null", __FUNCTION__);
params->tids.resize(tidsSize);
- params->tids.clear();
for (int i = 0; i < (int)tidsSize; ++i) {
LOG_ALWAYS_FATAL_IF(tids[i] <= 0, "ACpuHeadroomParams_setTids: Invalid non-positive tid %d",
tids[i]);
@@ -355,3 +362,10 @@ void ACpuHeadroomParams_destroy(ACpuHeadroomParams* _Nullable params) {
void AGpuHeadroomParams_destroy(AGpuHeadroomParams* _Nullable params) {
delete params;
}
+
+void ASystemHealth_setIHintManagerForTesting(void* iManager) {
+ if (iManager == nullptr) {
+ gSystemHealthManagerForTesting = nullptr;
+ }
+ gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager);
+}
diff --git a/native/android/tests/system_health/Android.bp b/native/android/tests/system_health/Android.bp
new file mode 100644
index 000000000000..30aeb77375ad
--- /dev/null
+++ b/native/android/tests/system_health/Android.bp
@@ -0,0 +1,66 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+cc_test {
+ name: "NativeSystemHealthUnitTestCases",
+
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+
+ srcs: ["NativeSystemHealthUnitTest.cpp"],
+
+ shared_libs: [
+ "libandroid",
+ "libbinder",
+ "libbinder_ndk",
+ "liblog",
+ "libpowermanager",
+ "libutils",
+ ],
+
+ static_libs: [
+ "libbase",
+ "libgmock",
+ "libgtest",
+ ],
+ stl: "c++_shared",
+
+ test_suites: [
+ "device-tests",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ header_libs: [
+ "libandroid_headers_private",
+ ],
+}
diff --git a/native/android/tests/system_health/NativeSystemHealthUnitTest.cpp b/native/android/tests/system_health/NativeSystemHealthUnitTest.cpp
new file mode 100644
index 000000000000..3f08fc66e392
--- /dev/null
+++ b/native/android/tests/system_health/NativeSystemHealthUnitTest.cpp
@@ -0,0 +1,231 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "NativeSystemHealthUnitTest"
+
+#include <aidl/android/os/IHintManager.h>
+#include <android/binder_manager.h>
+#include <android/binder_status.h>
+#include <android/system_health.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <system_health_private.h>
+
+#include <memory>
+#include <optional>
+#include <vector>
+
+using namespace std::chrono_literals;
+namespace hal = aidl::android::hardware::power;
+using aidl::android::os::CpuHeadroomParamsInternal;
+using aidl::android::os::GpuHeadroomParamsInternal;
+using aidl::android::os::IHintManager;
+using aidl::android::os::IHintSession;
+using aidl::android::os::SessionCreationConfig;
+using ndk::ScopedAStatus;
+using ndk::SpAIBinder;
+
+using namespace android;
+using namespace testing;
+
+class MockIHintManager : public IHintManager {
+public:
+ MOCK_METHOD(ScopedAStatus, createHintSessionWithConfig,
+ (const SpAIBinder& token, hal::SessionTag tag,
+ const SessionCreationConfig& creationConfig, hal::SessionConfig* config,
+ IHintManager::SessionCreationReturn* _aidl_return),
+ (override));
+ MOCK_METHOD(ScopedAStatus, setHintSessionThreads,
+ (const std::shared_ptr<IHintSession>& _, const ::std::vector<int32_t>& tids),
+ (override));
+ MOCK_METHOD(ScopedAStatus, getHintSessionThreadIds,
+ (const std::shared_ptr<IHintSession>& _, ::std::vector<int32_t>* tids), (override));
+ MOCK_METHOD(ScopedAStatus, getSessionChannel,
+ (const ::ndk::SpAIBinder& in_token,
+ std::optional<hal::ChannelConfig>* _aidl_return),
+ (override));
+ MOCK_METHOD(ScopedAStatus, closeSessionChannel, (), (override));
+ MOCK_METHOD(ScopedAStatus, getCpuHeadroom,
+ (const CpuHeadroomParamsInternal& _,
+ std::optional<hal::CpuHeadroomResult>* _aidl_return),
+ (override));
+ MOCK_METHOD(ScopedAStatus, getCpuHeadroomMinIntervalMillis, (int64_t*), (override));
+ MOCK_METHOD(ScopedAStatus, getGpuHeadroom,
+ (const GpuHeadroomParamsInternal& _,
+ std::optional<hal::GpuHeadroomResult>* _aidl_return),
+ (override));
+ MOCK_METHOD(ScopedAStatus, getGpuHeadroomMinIntervalMillis, (int64_t* _aidl_return),
+ (override));
+ MOCK_METHOD(ScopedAStatus, passSessionManagerBinder, (const SpAIBinder& sessionManager));
+ MOCK_METHOD(ScopedAStatus, registerClient,
+ (const std::shared_ptr<aidl::android::os::IHintManager::IHintManagerClient>& _,
+ aidl::android::os::IHintManager::HintManagerClientData* _aidl_return),
+ (override));
+ MOCK_METHOD(ScopedAStatus, getClientData,
+ (aidl::android::os::IHintManager::HintManagerClientData * _aidl_return),
+ (override));
+ MOCK_METHOD(SpAIBinder, asBinder, (), (override));
+ MOCK_METHOD(bool, isRemote, (), (override));
+};
+
+class NativeSystemHealthUnitTest : public Test {
+public:
+ void SetUp() override {
+ mMockIHintManager = ndk::SharedRefBase::make<NiceMock<MockIHintManager>>();
+ ASystemHealth_setIHintManagerForTesting(&mMockIHintManager);
+ ON_CALL(*mMockIHintManager, getClientData(_))
+ .WillByDefault(
+ DoAll(SetArgPointee<0>(mClientData), [] { return ScopedAStatus::ok(); }));
+ }
+
+ void TearDown() override {
+ ASystemHealth_setIHintManagerForTesting(nullptr);
+ }
+
+ IHintManager::HintManagerClientData mClientData{
+ .powerHalVersion = 6,
+ .maxCpuHeadroomThreads = 10,
+ .supportInfo{.headroom{
+ .isCpuSupported = true,
+ .isGpuSupported = true,
+ .cpuMinIntervalMillis = 999,
+ .gpuMinIntervalMillis = 998,
+ .cpuMinCalculationWindowMillis = 45,
+ .cpuMaxCalculationWindowMillis = 9999,
+ .gpuMinCalculationWindowMillis = 46,
+ .gpuMaxCalculationWindowMillis = 9998,
+ }},
+ };
+
+ std::shared_ptr<NiceMock<MockIHintManager>> mMockIHintManager = nullptr;
+};
+
+TEST_F(NativeSystemHealthUnitTest, headroomParamsValueRange) {
+ int64_t minIntervalMillis = 0;
+ int minCalculationWindowMillis = 0;
+ int maxCalculationWindowMillis = 0;
+ ASSERT_EQ(OK, ASystemHealth_getCpuHeadroomMinIntervalMillis(&minIntervalMillis));
+ ASSERT_EQ(OK,
+ ASystemHealth_getCpuHeadroomCalculationWindowRange(&minCalculationWindowMillis,
+ &maxCalculationWindowMillis));
+ ASSERT_EQ(minIntervalMillis, mClientData.supportInfo.headroom.cpuMinIntervalMillis);
+ ASSERT_EQ(minCalculationWindowMillis,
+ mClientData.supportInfo.headroom.cpuMinCalculationWindowMillis);
+ ASSERT_EQ(maxCalculationWindowMillis,
+ mClientData.supportInfo.headroom.cpuMaxCalculationWindowMillis);
+
+ ASSERT_EQ(OK, ASystemHealth_getGpuHeadroomMinIntervalMillis(&minIntervalMillis));
+ ASSERT_EQ(OK,
+ ASystemHealth_getGpuHeadroomCalculationWindowRange(&minCalculationWindowMillis,
+ &maxCalculationWindowMillis));
+ ASSERT_EQ(minIntervalMillis, mClientData.supportInfo.headroom.gpuMinIntervalMillis);
+ ASSERT_EQ(minCalculationWindowMillis,
+ mClientData.supportInfo.headroom.gpuMinCalculationWindowMillis);
+ ASSERT_EQ(maxCalculationWindowMillis,
+ mClientData.supportInfo.headroom.gpuMaxCalculationWindowMillis);
+}
+
+TEST_F(NativeSystemHealthUnitTest, getCpuHeadroom) {
+ CpuHeadroomParamsInternal internalParams1;
+ ACpuHeadroomParams* params2 = ACpuHeadroomParams_create();
+ ACpuHeadroomParams_setCalculationWindowMillis(params2, 200);
+ CpuHeadroomParamsInternal internalParams2;
+ internalParams2.calculationWindowMillis = 200;
+ ACpuHeadroomParams* params3 = ACpuHeadroomParams_create();
+ ACpuHeadroomParams_setCalculationType(params3, ACPU_HEADROOM_CALCULATION_TYPE_AVERAGE);
+ CpuHeadroomParamsInternal internalParams3;
+ internalParams3.calculationType = hal::CpuHeadroomParams::CalculationType::AVERAGE;
+ ACpuHeadroomParams* params4 = ACpuHeadroomParams_create();
+ int tids[3] = {1, 2, 3};
+ ACpuHeadroomParams_setTids(params4, tids, 3);
+ CpuHeadroomParamsInternal internalParams4;
+ internalParams4.tids = {1, 2, 3};
+
+ EXPECT_CALL(*mMockIHintManager, getCpuHeadroom(internalParams1, _))
+ .Times(Exactly(1))
+ .WillOnce(DoAll(SetArgPointee<1>(hal::CpuHeadroomResult::make<
+ hal::CpuHeadroomResult::globalHeadroom>(1.0f)),
+ [] { return ScopedAStatus::ok(); }));
+ EXPECT_CALL(*mMockIHintManager, getCpuHeadroom(internalParams2, _))
+ .Times(Exactly(1))
+ .WillOnce(DoAll(SetArgPointee<1>(hal::CpuHeadroomResult::make<
+ hal::CpuHeadroomResult::globalHeadroom>(2.0f)),
+ [] { return ScopedAStatus::ok(); }));
+ EXPECT_CALL(*mMockIHintManager, getCpuHeadroom(internalParams3, _))
+ .Times(Exactly(1))
+ .WillOnce(DoAll(SetArgPointee<1>(std::nullopt), [] { return ScopedAStatus::ok(); }));
+ EXPECT_CALL(*mMockIHintManager, getCpuHeadroom(internalParams4, _))
+ .Times(Exactly(1))
+ .WillOnce(DoAll(SetArgPointee<1>(hal::CpuHeadroomResult::make<
+ hal::CpuHeadroomResult::globalHeadroom>(4.0f)),
+ [] { return ScopedAStatus::ok(); }));
+
+ float headroom1 = 0.0f;
+ float headroom2 = 0.0f;
+ float headroom3 = 0.0f;
+ float headroom4 = 0.0f;
+ ASSERT_EQ(OK, ASystemHealth_getCpuHeadroom(nullptr, &headroom1));
+ ASSERT_EQ(OK, ASystemHealth_getCpuHeadroom(params2, &headroom2));
+ ASSERT_EQ(OK, ASystemHealth_getCpuHeadroom(params3, &headroom3));
+ ASSERT_EQ(OK, ASystemHealth_getCpuHeadroom(params4, &headroom4));
+ ASSERT_EQ(1.0f, headroom1);
+ ASSERT_EQ(2.0f, headroom2);
+ ASSERT_TRUE(isnan(headroom3));
+ ASSERT_EQ(4.0f, headroom4);
+
+ ACpuHeadroomParams_destroy(params2);
+ ACpuHeadroomParams_destroy(params3);
+ ACpuHeadroomParams_destroy(params4);
+}
+
+TEST_F(NativeSystemHealthUnitTest, getGpuHeadroom) {
+ GpuHeadroomParamsInternal internalParams1;
+ AGpuHeadroomParams* params2 = AGpuHeadroomParams_create();
+ AGpuHeadroomParams_setCalculationWindowMillis(params2, 200);
+ GpuHeadroomParamsInternal internalParams2;
+ internalParams2.calculationWindowMillis = 200;
+ AGpuHeadroomParams* params3 = AGpuHeadroomParams_create();
+ AGpuHeadroomParams_setCalculationType(params3, AGPU_HEADROOM_CALCULATION_TYPE_AVERAGE);
+ GpuHeadroomParamsInternal internalParams3;
+ internalParams3.calculationType = hal::GpuHeadroomParams::CalculationType::AVERAGE;
+
+ EXPECT_CALL(*mMockIHintManager, getGpuHeadroom(internalParams1, _))
+ .Times(Exactly(1))
+ .WillOnce(DoAll(SetArgPointee<1>(hal::GpuHeadroomResult::make<
+ hal::GpuHeadroomResult::globalHeadroom>(1.0f)),
+ [] { return ScopedAStatus::ok(); }));
+ EXPECT_CALL(*mMockIHintManager, getGpuHeadroom(internalParams2, _))
+ .Times(Exactly(1))
+ .WillOnce(DoAll(SetArgPointee<1>(hal::GpuHeadroomResult::make<
+ hal::GpuHeadroomResult::globalHeadroom>(2.0f)),
+ [] { return ScopedAStatus::ok(); }));
+ EXPECT_CALL(*mMockIHintManager, getGpuHeadroom(internalParams3, _))
+ .Times(Exactly(1))
+ .WillOnce(DoAll(SetArgPointee<1>(std::nullopt), [] { return ScopedAStatus::ok(); }));
+
+ float headroom1 = 0.0f;
+ float headroom2 = 0.0f;
+ float headroom3 = 0.0f;
+ ASSERT_EQ(OK, ASystemHealth_getGpuHeadroom(nullptr, &headroom1));
+ ASSERT_EQ(OK, ASystemHealth_getGpuHeadroom(params2, &headroom2));
+ ASSERT_EQ(OK, ASystemHealth_getGpuHeadroom(params3, &headroom3));
+ ASSERT_EQ(1.0f, headroom1);
+ ASSERT_EQ(2.0f, headroom2);
+ ASSERT_TRUE(isnan(headroom3));
+
+ AGpuHeadroomParams_destroy(params2);
+ AGpuHeadroomParams_destroy(params3);
+}
diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp
index 4180710534c3..bc273c2d0833 100644
--- a/native/graphics/jni/Android.bp
+++ b/native/graphics/jni/Android.bp
@@ -102,8 +102,13 @@ cc_defaults {
static_libs: ["libarect"],
fuzz_config: {
cc: [
+ // Alphabetical order -- assign to skia-android-triage@google.com
+ "danieldilan@google.com",
"dichenzhang@google.com",
- "scroggo@google.com",
+ "fmalita@google.com",
+ "jreck@google.com",
+ "nscobie@google.com",
+ "skia-android-triage@google.com",
],
asan_options: [
"detect_odr_violation=1",
diff --git a/nfc-non-updatable/flags/flags.aconfig b/nfc-non-updatable/flags/flags.aconfig
index 6b14a1ed3990..54ded0cddffa 100644
--- a/nfc-non-updatable/flags/flags.aconfig
+++ b/nfc-non-updatable/flags/flags.aconfig
@@ -197,3 +197,11 @@ flag {
description: "Expose constructor for ApduServiceInfo"
bug: "380892385"
}
+
+flag {
+ name: "nfc_hce_latency_events"
+ is_exported: true
+ namespace: "wallet_integration"
+ description: "Enables tracking latency for HCE"
+ bug: "379849603"
+}
diff --git a/packages/CarrierDefaultApp/res/values-iw/strings.xml b/packages/CarrierDefaultApp/res/values-iw/strings.xml
index 9e5a8b55bae6..9db81e0dded5 100644
--- a/packages/CarrierDefaultApp/res/values-iw/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-iw/strings.xml
@@ -5,7 +5,7 @@
<string name="android_system_label" msgid="2797790869522345065">"ספק שירות לנייד"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"ניצלת את מכסת הנתונים הסלולריים"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"חבילת הגלישה שלך הושבתה"</string>
- <string name="portal_notification_detail" msgid="2295729385924660881">"‏הקש כדי לעבור לאתר של %s"</string>
+ <string name="portal_notification_detail" msgid="2295729385924660881">"‏יש ללחוץ כדי לעבור לאתר של %s"</string>
<string name="no_data_notification_detail" msgid="3112125343857014825">"‏פנה לספק השירות %s"</string>
<string name="no_mobile_data_connection_title" msgid="7449525772416200578">"אין חיבור לחבילת גלישה"</string>
<string name="no_mobile_data_connection" msgid="544980465184147010">"‏אפשר להוסיף חבילת גלישה או חבילת נדידה באמצעות %s"</string>
diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml
index ba02bf696407..9476dc55e86a 100644
--- a/packages/CompanionDeviceManager/res/values-af/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-af/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Metgeseltoestel-bestuurder"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Gee die app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang tot &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Maak seker dat hierdie <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> se <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> aangeskakel is en hou jou <xliff:g id="PROFILE_NAME">%3$s</xliff:g> byderhand."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Geen toestelle gevind nie. Probeer later weer."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth en wi-fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"horlosie"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Kies ’n toestel wat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; moet bestuur"</string>
<string name="chooser_title" msgid="2235819929238267637">"Kies ’n <xliff:g id="PROFILE_NAME">%1$s</xliff:g> om op te stel"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Soek tans vir ’n <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Hierdie app sal toegelaat word om inligting te sinkroniseer, soos die naam van iemand wat bel, en sal toegang tot hierdie toestemmings op jou <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> hê"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Laat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toe om &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; te bestuur?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"toestel"</string>
diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml
index a6b78cb6dcb7..e53efcedd8cc 100644
--- a/packages/CompanionDeviceManager/res/values-am/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-am/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"አጃቢ የመሣሪያ አስተዳዳሪ"</string>
<string name="confirmation_title" msgid="2244241995958340998">"መተግበሪያው &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ን እንዲደርስ ይፈቀድለት?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"ይህ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> እንደበራለት ያረጋግጡ እና የእርስዎን <xliff:g id="PROFILE_NAME">%3$s</xliff:g> በአቅራቢያ ያቆዩ።"</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"ምንም መሣሪያዎች አልተገኙም። እባክዎ ቆይተው እንደገና ይሞክሩ።"</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"ብሉቱዝ"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"ብሉቱዝ እና Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ሰዓት"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; የሚያስተዳድረው መሣሪያ ይምረጡ"</string>
<string name="chooser_title" msgid="2235819929238267637">"የሚያዋቅሩት <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ይምረጡ"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> በመፈለግ ላይ"</string>
<string name="summary_watch" msgid="8134580124808507407">"ይህ መተግበሪያ እንደ የሚደውል ሰው ስም ያለ መረጃን እንዲያሰምር እና እነዚህን ፈቃዶች በእርስዎ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ላይ እንዲደርስ ይፈቀድለታል"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ን እንዲያስተዳድር ይፈቅዳሉ?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"መሣሪያ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml
index 5c07f3a16337..efbc6d92981a 100644
--- a/packages/CompanionDeviceManager/res/values-ar/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"تطبيق \"مدير الجهاز المصاحب\""</string>
<string name="confirmation_title" msgid="2244241995958340998">"‏هل تريد السماح لـ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بالوصول إلى &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;؟"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"يُرجى التأكّد من أنّ <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> مفعَّل في <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>، وجعل <xliff:g id="PROFILE_NAME">%3$s</xliff:g> بالقرب منك."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"لم يتم العثور على أي أجهزة. يُرجى إعادة المحاولة لاحقًا."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"البلوتوث"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"‏البلوتوث وWi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"الساعة"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"‏اختيار جهاز ليديره تطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"اختيار \"<xliff:g id="PROFILE_NAME">%1$s</xliff:g>\" للإعداد"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"جارٍ البحث عن <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"سيتم السماح لهذا التطبيق بمزامنة المعلومات، مثلاً اسم المتصل، واستخدام هذه الأذونات على <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"‏هل تريد السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بإدارة &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;؟"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"جهاز"</string>
diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml
index c07602afc050..9001a2c5e758 100644
--- a/packages/CompanionDeviceManager/res/values-as/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-as/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"কম্পেনিয়ন ডিভাইচ মেনেজাৰ"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; এপ্‌টোক &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; এক্সেছ কৰিবলৈ দিবনে?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"এই <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>টোৰ <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> অন হৈ থকাটো নিশ্চিত কৰক আৰু আপোনাৰ <xliff:g id="PROFILE_NAME">%3$s</xliff:g> আশে-পাশে ৰাখক।"</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"কোনো ডিভাইচ বিচাৰি পোৱা নগ’ল। অনুগ্ৰহ কৰি পাছত পুনৰ চেষ্টা কৰক।"</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"ব্লুটুথ"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"ৱাই-ফাই"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"ব্লুটুথ আৰু ৱাই-ফাই"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ঘড়ী"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;এ পৰিচালনা কৰিবলগীয়া এটা ডিভাইচ বাছনি কৰক"</string>
<string name="chooser_title" msgid="2235819929238267637">"ছেট আপ কৰিবলৈ এটা <xliff:g id="PROFILE_NAME">%1$s</xliff:g> বাছনি কৰক"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"কোনো <xliff:g id="PROFILE_NAME">%1$s</xliff:g> বিচাৰি থকা হৈছে"</string>
<string name="summary_watch" msgid="8134580124808507407">"এই এপ্‌টোক ফ’ন কৰা লোকৰ নামৰ দৰে তথ্য ছিংক কৰিবলৈ আৰু আপোনাৰ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ত এই অনুমতিসমূহ এক্সেছ কৰিবলৈ অনুমতি দিয়া হ’ব"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; পৰিচালনা কৰিবলৈ দিবনে?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"ডিভাইচ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml
index f053aa85a28f..2ffe84ead5b0 100644
--- a/packages/CompanionDeviceManager/res/values-az/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-az/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Kompanyon Cihaz Meneceri"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazına daxil olmaq icazəsi verilsin?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Bu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> cihazında <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> yandırılmalı və <xliff:g id="PROFILE_NAME">%3$s</xliff:g> yaxınlıqda saxlanılmalıdır."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Cihaz tapılmadı. Sonra cəhd edin."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth və Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"izləyin"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tərəfindən idarə ediləcək cihaz seçin"</string>
<string name="chooser_title" msgid="2235819929238267637">"Ayarlamaq üçün <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> axtarılır"</string>
<string name="summary_watch" msgid="8134580124808507407">"Bu tətbiq zəng edənin adı kimi məlumatları sinxronlaşdıra, <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> cihazında bu icazələrə daxil ola biləcək"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazını idarə etmək icazəsi verilsin?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"cihazda"</string>
diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
index 621ea2102747..ab52c39b34b9 100644
--- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Menadžer pridruženog uređaja"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Dozvolite da aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Uverite se da je za <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> uključen <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> i da u blizini imate <xliff:g id="PROFILE_NAME">%3$s</xliff:g>."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nije pronađen nijedan uređaj. Probajte ponovo kasnije."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"WiFi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth i WiFi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Odaberite uređaj kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> koji želite da podesite"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Traži se <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Ovoj aplikaciji će biti dozvoljeno da sinhronizuje podatke, poput imena pozivaoca, i pristupa tim dozvolama na uređaju <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Želite li da dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; upravlja uređajem &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"uređaj"</string>
diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml
index 0cdebcdbeffe..884101fe718d 100644
--- a/packages/CompanionDeviceManager/res/values-be/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-be/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Менеджар спадарожнай прылады"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Дазволіць праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; доступ да прылады &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Упэўніцеся, што на гэтай прыладзе (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) уключаны <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>, і трымайце <xliff:g id="PROFILE_NAME">%3$s</xliff:g> паблізу."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Прылады не знойдзены. Паўтарыце спробу пазней."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth і Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"гадзіннік"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Выберыце прыладу (<xliff:g id="APP_NAME">%1$s</xliff:g>), якой будзе кіраваць праграма &lt;strong&gt;&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Выберыце імя <xliff:g id="PROFILE_NAME">%1$s</xliff:g> для наладжвання"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g>: ідзе пошук"</string>
<string name="summary_watch" msgid="8134580124808507407">"Гэта праграма зможа сінхранізаваць інфармацыю (напрыклад, імя таго, хто звоніць) на вашай прыладзе тыпу \"<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>\" і атрымае наступныя дазволы"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Дазволіць праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; кіраваць прыладай &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"прылада"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml
index f522ab4807ae..9c3b94e6a0fe 100644
--- a/packages/CompanionDeviceManager/res/values-bg/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Да се разреши ли на приложението &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да осъществява достъп до устройството &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Функцията за <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> на <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> трябва да е включена и <xliff:g id="PROFILE_NAME">%3$s</xliff:g> да е близо."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Няма намерени устройства. Моля, опитайте отново по-късно."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth и Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Изберете устройство, което да се управлява от &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Изберете <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, за да го настроите"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Търси се <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Това приложение ще получи право да синхронизира различна информация, като например името на обаждащия се, и достъп до следните разрешения за вашия <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Разрешавате ли на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да управлява устройството &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"устройство"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml
index 61ec8c9bdf28..88db2a5d0975 100644
--- a/packages/CompanionDeviceManager/res/values-bn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; অ্যাক্সেস করার জন্য &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; অ্যাপকে কি অনুমতি দিতে চান?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>-এর <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> চালু আছে কিনা তা ভালোভাবে দেখে নিন এবং আপনার <xliff:g id="PROFILE_NAME">%3$s</xliff:g> কাছাকাছি রাখুন।"</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"কোনও ডিভাইস খুঁজে পাওয়া যায়নি। পরে আবার চেষ্টা করুন।"</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"ব্লুটুথ"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"ওয়াই-ফাই"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"ব্লুটুথ ও ওয়াই-ফাই"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ঘড়ি"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ম্যানেজ করা যাবে এমন একটি ডিভাইস বেছে নিন"</string>
<string name="chooser_title" msgid="2235819929238267637">"সেট-আপ করতে কোনও <xliff:g id="PROFILE_NAME">%1$s</xliff:g> বেছে নিন"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> খোঁজা হচ্ছে"</string>
<string name="summary_watch" msgid="8134580124808507407">"কল করছেন এমন কোনও ব্যক্তির নামের মতো তথ্য সিঙ্ক ও আপনার <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>-এ এইসব অনুমতি অ্যাক্সেস করার জন্য, এই অ্যাপকে অনুমতি দেওয়া হবে"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"আপনি কি &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ম্যানেজ করার জন্য &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-কে অনুমতি দেবেন?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"ডিভাইস"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml
index 00205f257315..e7f9b146133e 100644
--- a/packages/CompanionDeviceManager/res/values-bs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Prateći upravitelj uređaja"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Dozvoliti aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Provjerite ima li <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> uključen <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> i približite <xliff:g id="PROFILE_NAME">%3$s</xliff:g>."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nije pronađen nijedan uređaj. Pokušajte ponovo kasnije."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"WiFi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth i WiFi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Odaberite uređaj kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Odaberite <xliff:g id="PROFILE_NAME">%1$s</xliff:g> da postavite"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Traži se <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Aplikaciji će biti dozvoljeno da sinhronizira informacije, kao što je ime osobe koja upućuje poziv, i pristupa ovim odobrenjima koje sadržava vaš <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Dozvoliti aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da upravlja uređajem &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"uređaj"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml
index 662e297ae00c..8c0b117f29ea 100644
--- a/packages/CompanionDeviceManager/res/values-ca/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestor de dispositius complementaris"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Vols permetre que l\'aplicació &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; accedeixi a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Assegura\'t que aquest dispositiu (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) hagi activat <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> i mantén el <xliff:g id="PROFILE_NAME">%3$s</xliff:g> a prop."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"No s\'ha trobat cap dispositiu. Torna-ho a provar més tard."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"el Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"la Wi‑Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"el Bluetooth i la Wi‑Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"rellotge"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Tria un dispositiu perquè el gestioni &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Tria un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> per configurar"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"S\'està cercant un <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Aquesta aplicació podrà sincronitzar informació, com ara el nom d\'algú que truca, i accedir a aquests permisos al <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gestioni &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"dispositiu"</string>
diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml
index 6b110d3ae7b1..cde31af7ec97 100644
--- a/packages/CompanionDeviceManager/res/values-cs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Správce doprovodných zařízení"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; přístup k &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Zkontrolujte, zda je na tomto zařízení typu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> zapnutá funkce <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> a mějte své zařízení typu <xliff:g id="PROFILE_NAME">%3$s</xliff:g> poblíž."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nebyla nalezena žádná zařízení. Zkuste to znovu později."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth a Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Vyberte zařízení, které chcete spravovat pomocí aplikace &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Vyberte zařízení <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, které chcete nastavit"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Vyhledávání zařízení typu <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Tato aplikace bude moct synchronizovat údaje, jako je jméno volajícího, a získat na zařízení typu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> přístup k těmto oprávněním"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; spravovat zařízení &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"zařízení"</string>
diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml
index bbd01105c538..08a1ae1a8623 100644
--- a/packages/CompanionDeviceManager/res/values-da/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-da/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Medfølgende enhedsadministrator"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Vil du give appen &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; adgang til &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Sørg for, at <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> er aktiveret på denne <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>, og sørg for, at dit <xliff:g id="PROFILE_NAME">%3$s</xliff:g> er i nærheden."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Der blev ikke fundet nogen enheder. Prøv igen senere."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth og Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ur"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Vælg en enhed, som skal administreres af &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Vælg en <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, som du vil konfigurere"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Søger efter et <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Denne app får tilladelse til at synkronisere oplysninger, f.eks. navne på dem, der ringer, og adgang til disse tilladelser på din <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Vil du tillade, at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; administrerer &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"enhed"</string>
diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml
index 3eecfe71f6b6..30528c528518 100644
--- a/packages/CompanionDeviceManager/res/values-de/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-de/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Begleitgerät-Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Zulassen, dass &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; auf &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; zugreifen darf?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Achte darauf, dass die Option „<xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>“ auf diesem <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> aktiviert ist und dein Begleitgerät vom Typ „<xliff:g id="PROFILE_NAME">%3$s</xliff:g>“ in der Nähe ist."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Keine Geräte gefunden. Bitte versuche es später noch einmal."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"WLAN"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth &amp; WLAN"</string>
<string name="profile_name_watch" msgid="576290739483672360">"Smartwatch"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Gerät auswählen, das von &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; verwaltet werden soll"</string>
<string name="chooser_title" msgid="2235819929238267637">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> zum Einrichten auswählen"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Nach einem Begleitgerät vom Typ „<xliff:g id="PROFILE_NAME">%1$s</xliff:g>“ suchen"</string>
<string name="summary_watch" msgid="8134580124808507407">"Diese App darf dann Daten wie den Namen eines Anrufers synchronisieren und auf diese Berechtigungen auf deinem Gerät (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) zugreifen"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Zulassen, dass &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; das Gerät &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; verwalten darf?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"Gerät"</string>
diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml
index a26162f4e077..cffb365974f4 100644
--- a/packages/CompanionDeviceManager/res/values-el/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-el/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Διαχείριση συνοδευτικής εφαρμογής"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Να επιτρέπεται στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να έχει πρόσβαση στη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;;"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Βεβαιωθείτε ότι αυτή η συσκευή <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> έχει ενεργοποιημένο το <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> και κρατήστε τη συσκευή <xliff:g id="PROFILE_NAME">%3$s</xliff:g> κοντά."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Δεν βρέθηκαν συσκευές. Δοκιμάστε ξανά αργότερα."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth και Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ρολόι"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Επιλέξτε μια συσκευή για διαχείριση μέσω της εφαρμογής &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Επιλέξτε ένα προφίλ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> για ρύθμιση"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Αναζήτηση για <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Αυτή η εφαρμογή θα μπορεί να συγχρονίζει πληροφορίες, όπως το όνομα ενός ατόμου που σας καλεί, και να αποκτά πρόσβαση σε αυτές τις άδειες στη συσκευή <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Να επιτρέπεται στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να διαχειρίζεται τη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ;"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"συσκευή"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
index b5fea9f22c15..8590e9f96f1c 100644
--- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Allow the app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Make sure that this <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> has <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> turned on and keep your <xliff:g id="PROFILE_NAME">%3$s</xliff:g> nearby."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"No devices found. Please try again later."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth and Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Choose a device to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to set up"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Looking for a <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"device"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
index 42c6b888cddc..041966ec0ce4 100644
--- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Allow the app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Make sure this <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> has <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> turned on, and keep your <xliff:g id="PROFILE_NAME">%3$s</xliff:g> nearby."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"No devices found. Please try again later."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth and Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Choose a device to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to set up"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Looking for a <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"device"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
index b5fea9f22c15..8590e9f96f1c 100644
--- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Allow the app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Make sure that this <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> has <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> turned on and keep your <xliff:g id="PROFILE_NAME">%3$s</xliff:g> nearby."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"No devices found. Please try again later."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth and Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Choose a device to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to set up"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Looking for a <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"device"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
index b5fea9f22c15..8590e9f96f1c 100644
--- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Allow the app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Make sure that this <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> has <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> turned on and keep your <xliff:g id="PROFILE_NAME">%3$s</xliff:g> nearby."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"No devices found. Please try again later."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth and Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Choose a device to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to set up"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Looking for a <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"device"</string>
diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
index a5d00a3186e0..88ae3ed0356b 100644
--- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Administrador de dispositivo complementario"</string>
<string name="confirmation_title" msgid="2244241995958340998">"¿Quieres permitir que la app de &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Asegúrate de que este <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> tenga activado el <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> y mantén cerca tu <xliff:g id="PROFILE_NAME">%3$s</xliff:g>."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"No se encontraron dispositivos. Vuelve a intentarlo más tarde."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth y Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Elige un dispositivo para que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lo administre"</string>
<string name="chooser_title" msgid="2235819929238267637">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para configurar"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Buscando un <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Esta app podrá sincronizar información, como el nombre de alguien cuando te llame, y acceder a los siguientes permisos en tu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; administre &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml
index fc6e6c55557a..ac8c79a61496 100644
--- a/packages/CompanionDeviceManager/res/values-es/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestor de dispositivos complementario"</string>
<string name="confirmation_title" msgid="2244241995958340998">"¿Permitir que la aplicación &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Asegúrate de que este dispositivo (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) tenga el <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> activado y mantén tu <xliff:g id="PROFILE_NAME">%3$s</xliff:g> cerca."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"No se ha encontrado ningún dispositivo. Inténtalo de nuevo más tarde."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth y Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Elige un dispositivo para que lo gestione &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Elige el <xliff:g id="PROFILE_NAME">%1$s</xliff:g> que quieras configurar"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Buscando <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Esta aplicación podrá sincronizar información, como el nombre de la persona que llama, y acceder a estos permisos de tu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"¿Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gestione &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml
index 2cbb44134d31..9c22847df868 100644
--- a/packages/CompanionDeviceManager/res/values-et/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-et/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Kaasseadme haldur"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Kas anda rakendusele &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; juurdepääs seadmele &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Veenduge, et seadmes <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> oleks <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> sisse lülitatud, ja hoidke oma seade <xliff:g id="PROFILE_NAME">%3$s</xliff:g> läheduses."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Seadmeid ei leitud. Proovige hiljem uuesti."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"WiFi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth ja WiFi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"käekell"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Valige seade, mida haldab rakendus &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Valige <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, mis seadistada"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Seadme <xliff:g id="PROFILE_NAME">%1$s</xliff:g> otsimine"</string>
<string name="summary_watch" msgid="8134580124808507407">"Sellel rakendusel lubatakse sünkroonida teavet (nt helistaja nime) ja antakse juurdepääs nendele lubadele, mille asukoht on teie <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Lubage rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; hallata seadet &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"seade"</string>
diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml
index 3a49cf94ca6b..c52c2b982f02 100644
--- a/packages/CompanionDeviceManager/res/values-eu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gailu osagarriaren kudeatzailea"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; gailua erabiltzeko baimena eman nahi diozu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Ziurtatu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> honen <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> aktibatuta dagoela, eta eduki <xliff:g id="PROFILE_NAME">%3$s</xliff:g> hurbil."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Ez da aurkitu gailurik. Saiatu berriro geroago."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetootha"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wifia"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetootha eta wifia"</string>
<string name="profile_name_watch" msgid="576290739483672360">"erlojua"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Aukeratu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioak kudeatu behar duen gailua"</string>
<string name="chooser_title" msgid="2235819929238267637">"Aukeratu konfiguratu nahi duzun <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> baten bila"</string>
<string name="summary_watch" msgid="8134580124808507407">"Informazioa sinkronizatzeko (esate baterako, deitzaileen izenak) eta hauetarako baimenak izango ditu aplikazioak <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> erabiltzean:"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; kudeatzeko baimena eman nahi diozu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"gailua"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index 481522500140..2f4f9380171e 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"مدیر دستگاه مرتبط"</string>
<string name="confirmation_title" msgid="2244241995958340998">"‏به برنامه &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه داده شود به &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; دسترسی پیدا کند؟"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"مطمئن شوید <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> در این <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> روشن باشد و <xliff:g id="PROFILE_NAME">%3$s</xliff:g> را نزدیک نگه دارید."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"دستگاهی پیدا نشد. لطفاً بعداً دوباره امتحان کنید."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"بلوتوث"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"‏بلوتوث و Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ساعت"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"‏انتخاب دستگاه برای مدیریت کردن با &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"انتخاب <xliff:g id="PROFILE_NAME">%1$s</xliff:g> برای راه‌اندازی"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"درحال یافتن <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"به این برنامه اجازه داده می‌شود اطلاعاتی مثل نام تماس‌گیرنده را همگام‌سازی کند و به این اجازه‌ها در <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> شما دسترسی داشته باشد"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه داده شود &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; را مدیریت کند؟"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"دستگاه"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml
index 6e13d6cf542e..be4076abde4b 100644
--- a/packages/CompanionDeviceManager/res/values-fi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Sallitaanko, että soellus (&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;) saa pääsyn laitteeseen: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Varmista, että <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> on päällä laitteella (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>), ja pidä <xliff:g id="PROFILE_NAME">%3$s</xliff:g> lähellä."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Laitteita ei löydy. Yritä myöhemmin uudelleen."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth ja Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"kello"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Valitse laite, jota &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; hallinnoi"</string>
<string name="chooser_title" msgid="2235819929238267637">"Valitse <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, niin voit suorittaa käyttöönoton"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Etsitään tätä: <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Sovellus saa luvan synkronoida tietoja (esimerkiksi soittajan nimen) ja pääsyn näihin lupiin laitteella (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Salli, että &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; saa ylläpitää laitetta: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"laite"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index 73a180b586d3..0aa462bee90e 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -18,9 +18,15 @@
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\'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="message_discovery_soft_timeout" msgid="473346859407859161">"Assurez-vous que le <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> est activé sur cet appareil (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) et gardez votre <xliff:g id="PROFILE_NAME">%3$s</xliff:g> à proximité."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Aucun appareil détecté. Veuillez réessayer plus tard."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth et Wi-Fi"</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="single_device_title" msgid="4199861437545438606">"À la recherche de l\'appareil suivant : <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"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_TYPE">%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>
diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml
index 0c0ae7912dc4..e7741c42850e 100644
--- a/packages/CompanionDeviceManager/res/values-fr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestionnaire d\'appareils associés"</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="message_discovery_soft_timeout" msgid="473346859407859161">"Assurez-vous que le <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> de votre <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> est activé et gardez votre <xliff:g id="PROFILE_NAME">%3$s</xliff:g> à proximité."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Aucun appareil trouvé. Veuillez réessayer plus tard."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth et Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Sélectionner l\'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">"Sélectionner votre <xliff:g id="PROFILE_NAME">%1$s</xliff:g> à configurer"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Recherche de l\'appareil suivant : <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Cette appli sera autorisée à synchroniser des infos (comme le nom de l\'appelant) et disposera de ces autorisations sur votre <xliff:g id="DEVICE_TYPE">%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>
diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml
index 71eb86ff32f3..bf58761da26f 100644
--- a/packages/CompanionDeviceManager/res/values-gl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Xestor de dispositivos complementarios"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Queres permitir que a aplicación &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda ao dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Cómpre que este <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> teña activada a conexión <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> e que estea preto do <xliff:g id="PROFILE_NAME">%3$s</xliff:g>."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Non se atopou ningún dispositivo. Téntao de novo máis tarde."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wifi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth e wifi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"reloxo"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Escolle un dispositivo para que o xestione a aplicación &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Escolle o perfil (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) que queiras configurar"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Buscando <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Esta aplicación poderá sincronizar información (por exemplo, o nome de quen chama) e acceder a estes permisos do dispositivo (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Queres permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; xestione o dispositivo (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;)?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml
index 9b20886bc0af..d3db96eedb6b 100644
--- a/packages/CompanionDeviceManager/res/values-gu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"કમ્પેનિયન ડિવાઇસ મેનેજર"</string>
<string name="confirmation_title" msgid="2244241995958340998">"શું &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ને ઍક્સેસ કરવા માટે, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ઍપને મંજૂરી આપીએ?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"ખાતરી કરો કે આ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> દ્વારા <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ચાલુ કરવામાં આવી છે અને તમારી <xliff:g id="PROFILE_NAME">%3$s</xliff:g> નજીકમાં રાખો."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"કોઈ ડિવાઇસ મળ્યું નથી. કૃપા કરીને થોડા સમય પછી ફરી પ્રયાસ કરો."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"બ્લૂટૂથ"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"વાઇ-ફાઇ"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"બ્લૂટૂથ અને વાઇ-ફાઇ"</string>
<string name="profile_name_watch" msgid="576290739483672360">"સ્માર્ટવૉચ"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; દ્વારા મેનેજ કરવા માટે કોઈ ડિવાઇસ પસંદ કરો"</string>
<string name="chooser_title" msgid="2235819929238267637">"સેટઅપ કરવા માટે કોઈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> પસંદ કરો"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> શોધી રહ્યાં છીએ"</string>
<string name="summary_watch" msgid="8134580124808507407">"આ ઍપને, કૉલ કરનાર વ્યક્તિનું નામ જેવી માહિતી સિંક કરવાની અને તમારા <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> પર આ પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; મેનેજ કરવા માટે મંજૂરી આપીએ?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"ડિવાઇસ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index 7224896392e4..2d38a00e9fcb 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"कंपैनियन डिवाइस मैनेजर"</string>
<string name="confirmation_title" msgid="2244241995958340998">"क्या &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; को ऐक्सेस करने के लिए &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ऐप्लिकेशन को अनुमति देनी है?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"पक्का करें कि इस <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> का <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> चालू हो और <xliff:g id="PROFILE_NAME">%3$s</xliff:g> आपके आस-पास हो."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"कोई डिवाइस नहीं मिला. कृपया बाद में कोशिश करें."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"ब्लूटूथ"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"वाई-फ़ाई"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"ब्लूटूथ और वाई-फ़ाई"</string>
<string name="profile_name_watch" msgid="576290739483672360">"स्मार्टवॉच"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; से मैनेज किया जाने वाला डिवाइस चुनें"</string>
<string name="chooser_title" msgid="2235819929238267637">"सेट अप करने के लिए कोई <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चुनें"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> को ढूंढा जा रहा है"</string>
<string name="summary_watch" msgid="8134580124808507407">"यह ऐप्लिकेशन, आपके <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> पर इन अनुमतियों को ऐक्सेस करने के साथ-साथ कॉल करने वाले व्यक्ति के नाम जैसी जानकारी सिंक कर पाएगा"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"क्या &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; मैनेज करने की अनुमति देनी है?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"डिवाइस"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml
index 0b769f036f32..d002c9ce0f82 100644
--- a/packages/CompanionDeviceManager/res/values-hr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Upravitelj popratnih uređaja"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Želite li dopustiti aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Provjerite je li na uređaju <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> uključen <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> i držite <xliff:g id="PROFILE_NAME">%3$s</xliff:g> u blizini."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nije pronađen nijedan uređaj. Pokušajte ponovo kasnije."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth i Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"satom"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Odaberite uređaj kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> koji želite postaviti"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Traži se <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Aplikacija će moći sinkronizirati podatke kao što je ime pozivatelja i pristupiti tim dopuštenjima na vašem uređaju <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Dopustiti aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da upravlja uređajem &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"uređaj"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml
index 69bd41b28f63..8b11dac56f9c 100644
--- a/packages/CompanionDeviceManager/res/values-hu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Társeszközök kezelője"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Engedélyezi a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazás számára, hogy hozzáférjen a következőhöz: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Győződjön meg arról, hogy a <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> be van kapcsolva ezen a(z) <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> eszközön, és hogy a(z) <xliff:g id="PROFILE_NAME">%3$s</xliff:g> eszköz a közelben van."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nem található eszköz. Próbálja újra később."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth és Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"óra"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"A(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazással kezelni kívánt eszköz kiválasztása"</string>
<string name="chooser_title" msgid="2235819929238267637">"Válassza ki a beállítani kívánt <xliff:g id="PROFILE_NAME">%1$s</xliff:g> nevet."</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Keresés – <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Ez az alkalmazás képes lesz szinkronizálni információkat (például a hívó fél nevét), és hozzáférhet majd ezekhez az engedélyekhez a következőn: <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Engedélyezi, hogy a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; kezelje a következő eszközt: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"eszköz"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml
index 27cd9751d824..9d45928eeb5f 100644
--- a/packages/CompanionDeviceManager/res/values-hy/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Թույլատրե՞լ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին կառավարել &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; սարքը"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Համոզվեք, որ այս <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> սարքի <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>-ը միացված է, և ձեր <xliff:g id="PROFILE_NAME">%3$s</xliff:g>-ը մոտ պահեք։"</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Սարքեր չեն գտնվել։ Փորձեք ավելի ուշ։"</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth և Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ժամացույց"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Ընտրեք սարքը, որը պետք է կառավարվի &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածի միջոցով"</string>
<string name="chooser_title" msgid="2235819929238267637">"Կարգավորելու համար ընտրեք <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ը"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> սարքի որոնում"</string>
<string name="summary_watch" msgid="8134580124808507407">"Այս հավելվածը կկարողանա համաժամացնել տվյալները, օր․՝ զանգողի անունը, և կստանա հետևյալ թույլտվությունները ձեր <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ում"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Թույլատրե՞լ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին կառավարել &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; սարքը"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"սարք"</string>
diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml
index 6ec3392a02ad..9c9144c4f63d 100644
--- a/packages/CompanionDeviceManager/res/values-in/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-in/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Pengelola Perangkat Pendamping"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Izinkan aplikasi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; mengakses &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Pastikan <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ini mengaktifkan <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>, dan letakkan <xliff:g id="PROFILE_NAME">%3$s</xliff:g> di dekat Anda."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Perangkat tidak ditemukan. Coba lagi nanti."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth dan Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"smartwatch"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Pilih perangkat untuk dikelola oleh &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk disiapkan"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Mencari <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Aplikasi ini akan diizinkan menyinkronkan info, seperti nama penelepon, dan mengakses izin ini di <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> Anda"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; mengelola &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"perangkat"</string>
diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml
index f1b6ced64d69..1247aaef319f 100644
--- a/packages/CompanionDeviceManager/res/values-is/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-is/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Stjórnun fylgdartækja"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Veita forritinu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aðgang að &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Gakktu úr skugga um að kveikt sé á <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> í <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> og hafðu <xliff:g id="PROFILE_NAME">%3$s</xliff:g> nálægt."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Engin tæki fundust. Reyndu aftur síðar."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth og Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"úr"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Veldu tæki sem &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; á að stjórna"</string>
<string name="chooser_title" msgid="2235819929238267637">"Veldu <xliff:g id="PROFILE_NAME">%1$s</xliff:g> til að setja upp"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Leitar að <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Þetta forrit fær heimild til að samstilla upplýsingar, t.d. nafn þess sem hringir, og fær aðgang að eftirfarandi heimildum í <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að stjórna &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"tæki"</string>
diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml
index 2afdcbaab8bf..3fa0419832e8 100644
--- a/packages/CompanionDeviceManager/res/values-it/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-it/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestione dispositivi associati"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Vuoi consentire all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di accedere a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Assicurati che il <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> abbia il <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> attivo e tieni l’<xliff:g id="PROFILE_NAME">%3$s</xliff:g> vicino."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nessun dispositivo trovato. Riprova più tardi."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth e Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"orologio"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Scegli un dispositivo che sia gestito da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Scegli un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> da configurare"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Ricerca di un <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Questa app potrà sincronizzare informazioni, ad esempio il nome di un chiamante, e accedere alle seguenti autorizzazioni <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Vuoi consentire all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di gestire &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml
index 4181e6278d4f..f775a7f16f81 100644
--- a/packages/CompanionDeviceManager/res/values-iw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ניהול מכשיר מותאם"</string>
<string name="confirmation_title" msgid="2244241995958340998">"‏לאפשר לאפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; לגשת אל &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"צריך לוודא שה-<xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> מופעל ב<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>, ושה<xliff:g id="PROFILE_NAME">%3$s</xliff:g> בקרבת מקום."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"לא נמצאו מכשירים. אפשר לנסות שוב מאוחר יותר."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"‏חיבור Wi-Fi ו-Bluetooth"</string>
<string name="profile_name_watch" msgid="576290739483672360">"שעון"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"‏בחירה של מכשיר לניהול באמצעות &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"בחירת <xliff:g id="PROFILE_NAME">%1$s</xliff:g> להגדרה"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"מתבצע חיפוש של <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"האפליקציה הזו תוכל לסנכרן מידע, כמו השם של מישהו שמתקשר, ולגשת להרשאות האלה ב<xliff:g id="DEVICE_TYPE">%1$s</xliff:g> שלך"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"‏מתן הרשאה לאפליקציה ‎&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&amp;g;‎‏ לנהל את ‎&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;‎‏"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"מכשיר"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml
index 5974c6b1679c..0ad41cd72916 100644
--- a/packages/CompanionDeviceManager/res/values-ja/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"コンパニオン デバイス マネージャー"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; アプリに &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; へのアクセスを許可しますか?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"この<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>の<xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>が ON であることを確認し、<xliff:g id="PROFILE_NAME">%3$s</xliff:g>を近くに置いてください。"</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"デバイスが見つかりません。しばらくしてからもう一度お試しください。"</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth、Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ウォッチ"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; の管理対象となるデバイスの選択"</string>
<string name="chooser_title" msgid="2235819929238267637">"設定する<xliff:g id="PROFILE_NAME">%1$s</xliff:g>の選択"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g>を探しています"</string>
<string name="summary_watch" msgid="8134580124808507407">"このアプリは、通話相手の名前などの情報を同期したり、<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>の以下の権限にアクセスしたりできるようになります"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; の管理を許可しますか?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"デバイス"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml
index de1c8e1a19b7..d9bc50a4f9f5 100644
--- a/packages/CompanionDeviceManager/res/values-ka/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"კომპანიონი მოწყობილობების მენეჯერი"</string>
<string name="confirmation_title" msgid="2244241995958340998">"ნებას რთავთ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; აპს, წვდომა ჰქონდეს &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; მოწყობილობაზე?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"დარწმუნდით, რომ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>-ზე ჩართულია <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> და <xliff:g id="PROFILE_NAME">%3$s</xliff:g> იქონიეთ ახლოს."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"მოწყობილობები ვერ მოიძებნა. ცადეთ მოგვიანებით."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth და Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"საათი"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"აირჩიეთ მოწყობილობა, რომელიც უნდა მართოს &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; აპმა"</string>
<string name="chooser_title" msgid="2235819929238267637">"აირჩიეთ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> დასაყენებლად"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g>-ის ძებნა"</string>
<string name="summary_watch" msgid="8134580124808507407">"ეს აპი შეძლებს ინფორმაციის (მაგალითად, იმ ადამიანის სახელი, რომელიც გირეკავთ) სინქრონიზებას და თქვენს <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>-ზე არსებულ ამ ნებართვებზე წვდომას"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"ნება დართეთ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>-ს&lt;/strong&gt; მართოს &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"მოწყობილობა"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml
index 27492a035e8a..2fd8d96dfd7f 100644
--- a/packages/CompanionDeviceManager/res/values-kk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;? құрылғысына кіруге рұқсат беріңіз"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Құрылғыдағы (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> қосулы болуын тексеріп, <xliff:g id="PROFILE_NAME">%3$s</xliff:g> құрылғысын маңайында ұстаңыз."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Ешқандай құрылғы табылмады. Кейінірек қайталап көріңіз."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth және Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"сағат"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; арқылы басқарылатын құрылғыны таңдаңыз"</string>
<string name="chooser_title" msgid="2235819929238267637">"Реттеу үшін <xliff:g id="PROFILE_NAME">%1$s</xliff:g> таңдаңыз"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> құрылғысын іздеу"</string>
<string name="summary_watch" msgid="8134580124808507407">"Бұл қолданба қоңырау шалушының аты сияқты деректі синхрондай алады және құрылғыдағы (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) осы рұқсаттарды пайдалана алады."</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; құрылғысын басқаруға рұқсат беру керек пе?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"құрылғы"</string>
diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml
index 55216e590683..77e2396cd3c9 100644
--- a/packages/CompanionDeviceManager/res/values-km/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-km/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"កម្មវិធី​គ្រប់​គ្រង​ឧបករណ៍ដៃគូ"</string>
<string name="confirmation_title" msgid="2244241995958340998">"អនុញ្ញាតឱ្យកម្មវិធី &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ចូលប្រើ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ឬ?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"សូមប្រាកដថា<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>នេះបានបើក<xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> និងទុក<xliff:g id="PROFILE_NAME">%3$s</xliff:g>នៅ​ជិតអ្នក។"</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"រកមិន​ឃើញ​ឧបករណ៍ទេ។ សូមព្យាយាមម្ដងទៀតនៅពេលក្រោយ។"</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"ប៊្លូធូស"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"ប៊្លូធូស និង Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"នាឡិកា"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"ជ្រើសរើសឧបករណ៍ ដើម្បីដាក់ក្រោម​ការគ្រប់គ្រងរបស់ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"ជ្រើសរើស <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ដើម្បីរៀបចំ"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"កំពុងស្វែងរក<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"កម្មវិធីនេះនឹងត្រូវបានអនុញ្ញាតឱ្យធ្វើសមកាលកម្មព័ត៌មាន ដូចជាឈ្មោះមនុស្សដែលហៅទូរសព្ទជាដើម និងចូលប្រើការអនុញ្ញាតទាំងនេះនៅលើ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> របស់អ្នក"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; គ្រប់គ្រង &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ឬ?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"ឧបករណ៍"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml
index 7dcb4e379637..8320708da102 100644
--- a/packages/CompanionDeviceManager/res/values-kn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ಕಂಪ್ಯಾನಿಯನ್ ಸಾಧನ ನಿರ್ವಾಹಕರು"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಅನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸಬೇಕೆ?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"ಈ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ನಲ್ಲಿ <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ಆನ್ ಆಗಿದೆಯೇ ಎಂಬುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ ಮತ್ತು ನಿಮ್ಮ <xliff:g id="PROFILE_NAME">%3$s</xliff:g> ಅನ್ನು ಸಮೀಪಲ್ಲಿಡಿ."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"ಯಾವುದೇ ಸಾಧನಗಳು ಕಂಡುಬಂದಿಲ್ಲ. ನಂತರ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"ಬ್ಲೂಟೂತ್"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"ವೈ-ಫೈ"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"ಬ್ಲೂಟೂತ್ ಮತ್ತು ವೈ-ಫೈ"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ವೀಕ್ಷಿಸಿ"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಮೂಲಕ ನಿರ್ವಹಿಸಬೇಕಾದ ಸಾಧನವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="chooser_title" msgid="2235819929238267637">"ಸೆಟಪ್ ಮಾಡಲು <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ಅನ್ನು ಆರಿಸಿ"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ಗಾಗಿ ಹುಡುಕಲಾಗುತ್ತಿದೆ"</string>
<string name="summary_watch" msgid="8134580124808507407">"ಯಾರೋ ಕರೆ ಮಾಡುವವರ ಹೆಸರಿನಂತಹ ಮಾಹಿತಿಯನ್ನು ಸಿಂಕ್ ಮಾಡಲು ಮತ್ತು <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ನಲ್ಲಿ ಈ ಅನುಮತಿಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್‌ ಮಾಡಲು ಈ ಆ್ಯಪ್ ಅನ್ನು ಅನುಮತಿಸಲಾಗುತ್ತದೆ"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;? ನಿರ್ವಹಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"ಸಾಧನ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index ff8ed1638062..ee4db7d681ad 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"부속 기기 관리자"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 앱에서 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;에 액세스하도록 허용하시겠습니까?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"이 <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>에서 <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> 기능을 사용 설정하고 <xliff:g id="PROFILE_NAME">%3$s</xliff:g> 기기를 근처에 두세요."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"기기를 찾을 수 없습니다. 나중에 다시 시도해 주세요."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"블루투스"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"블루투스 및 Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"시계"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 관리할 기기 선택"</string>
<string name="chooser_title" msgid="2235819929238267637">"설정할 <xliff:g id="PROFILE_NAME">%1$s</xliff:g> 선택"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> 찾는 중"</string>
<string name="summary_watch" msgid="8134580124808507407">"이 앱이 정보(예: 발신자 이름)를 동기화하고 <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>에서 이러한 권한에 액세스할 수 있게 됩니다."</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 기기를 관리하도록 허용하시겠습니까?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"기기"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml
index 8c39dd2dea6f..af01cf7c8d7d 100644
--- a/packages/CompanionDeviceManager/res/values-ky/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; түзмөгүнө кирүүгө уруксат бересизби?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"<xliff:g id="DEVICE_TYPE">%1$s</xliff:g> түзмөгүңүздөгү <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>ыкмасын күйгүзүп, <xliff:g id="PROFILE_NAME">%3$s</xliff:g> профилиңизди жакын кармаңыз."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Түзмөктөр табылган жок. Кийинчерээк кайталап көрүңүз."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth жана Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"саат"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; аркылуу башкарыла турган түзмөктү тандаңыз"</string>
<string name="chooser_title" msgid="2235819929238267637">"Тууралоо үчүн <xliff:g id="PROFILE_NAME">%1$s</xliff:g> тандаңыз"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> профилин издөө"</string>
<string name="summary_watch" msgid="8134580124808507407">"Бул колдонмого маалыматты, мисалы, чалып жаткан адамдын аты-жөнүн шайкештирүүгө жана <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> түзмөгүңүздө төмөнкүлөрдү аткарууга уруксат берилет"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; түзмөгүн тескөөгө уруксат бересизби?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"түзмөк"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml
index a7cc51e55c2d..d7f777d3c8f1 100644
--- a/packages/CompanionDeviceManager/res/values-lo/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ຕົວຈັດການອຸປະກອນປະກອບ"</string>
<string name="confirmation_title" msgid="2244241995958340998">"ອະນຸຍາດໃຫ້ແອັບ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ເຂົ້າເຖິງ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ບໍ?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"ກວດສອບໃຫ້ໝັ້ນໃຈວ່າ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ເຄື່ອງນີ້ເປີດ <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ຢູ່ ແລະ ໃຫ້ຢູ່ໃກ້ກັບ <xliff:g id="PROFILE_NAME">%3$s</xliff:g>."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"ບໍ່ພົບອຸປະກອນ. ກະລຸນາລອງໃໝ່ໃນພາຍຫຼັງ."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth ແລະ Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ໂມງ"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"ເລືອກອຸປະກອນທີ່ຈະໃຫ້ມີການຈັດການໂດຍ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"ເລືອກ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ທີ່ຈະຕັ້ງຄ່າ"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"ກຳລັງຊອກຫາ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"ແອັບນີ້ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ຊິ້ງຂໍ້ມູນ ເຊັ່ນ: ຊື່ຂອງຄົນທີ່ໂທເຂົ້າ ແລະ ສິດເຂົ້າເຖິງການອະນຸຍາດເຫຼົ່ານີ້ຢູ່ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ຂອງທ່ານ"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"ອະນຸຍາດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ຈັດການ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ບໍ?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"ອຸປະກອນ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml
index b537508b8f7b..9fcf0fa22c67 100644
--- a/packages/CompanionDeviceManager/res/values-lt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Leisti programai &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pasiekti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Įsitikinkite, kad šiame įrenginyje (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) įjungta <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ir kad <xliff:g id="PROFILE_NAME">%3$s</xliff:g> yra netoliese."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nerasta jokių įrenginių. Vėliau bandykite dar kartą."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"„Bluetooth“ ir „Wi-Fi“"</string>
<string name="profile_name_watch" msgid="576290739483672360">"laikrodį"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Įrenginio, kuris bus valdomas naudojant programą &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;, pasirinkimas"</string>
<string name="chooser_title" msgid="2235819929238267637">"Norimo nustatyti <xliff:g id="PROFILE_NAME">%1$s</xliff:g> pasirinkimas"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Ieškoma <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Šiai programai bus leidžiama sinchronizuoti tam tikrą informaciją, pvz., skambinančio asmens vardą, ir pasiekti toliau nurodytus <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> leidimus"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Leisti &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; valdyti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"įrenginio"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml
index e310fe2ca887..39b158d58666 100644
--- a/packages/CompanionDeviceManager/res/values-lv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Palīgierīču pārzinis"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Vai atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; piekļūt lietotnei &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Noteikti ieslēdziet šajā ierīcē (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> un gādājiet, lai <xliff:g id="PROFILE_NAME">%3$s</xliff:g> būtu tuvumā."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nav atrasta neviena ierīce. Lūdzu, vēlāk mēģiniet vēlreiz."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi‑Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth un Wi‑Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"pulkstenis"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Izvēlieties ierīci, ko pārvaldīt lietotnē &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Jāizvēlas <xliff:g id="PROFILE_NAME">%1$s</xliff:g> iestatīšanai"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Tiek meklēta ierīce (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>)…"</string>
<string name="summary_watch" msgid="8134580124808507407">"Šī lietotne drīkstēs sinhronizēt informāciju, piemēram, zvanītāja vārdu, un piekļūt šīm <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> atļaujām."</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Vai atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; piekļūt ierīcei &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"ierīce"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml
index 08b422bc12cf..107895d5a8da 100644
--- a/packages/CompanionDeviceManager/res/values-mk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Дозволувате апликацијата &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да пристапува до &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Погрижете се <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> да биде вклучен на овој <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> и вашиот <xliff:g id="PROFILE_NAME">%3$s</xliff:g> да биде во близина."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Не се најдени уреди. Обидете се повторно подоцна."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth и Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Изберете уред со којшто ќе управува &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Изберете <xliff:g id="PROFILE_NAME">%1$s</xliff:g> за поставување"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Се бара <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Оваа апликација ќе има дозвола да ги синхронизира податоците како што се имињата на јавувачите и да пристапува до следниве дозволи на вашиот <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Ќе дозволите &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да управува со &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"уред"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml
index ab9671ed540f..de50fc721522 100644
--- a/packages/CompanionDeviceManager/res/values-ml/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"കമ്പാനിയൻ ഉപകരണ മാനേജർ"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ആക്‌സസ് ചെയ്യാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്ന ആപ്പിനെ അനുവദിക്കണോ?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"ഈ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> എന്നതിൽ <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ഓണാക്കിയിട്ടുണ്ടെന്ന് ഉറപ്പുവരുത്തുക, നിങ്ങളുടെ <xliff:g id="PROFILE_NAME">%3$s</xliff:g> സമീപം വയ്ക്കുക."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"ഉപകരണങ്ങളൊന്നും കണ്ടെത്തിയില്ല. പിന്നീട് വീണ്ടും ശ്രമിക്കുക."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"വൈഫൈ"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth-ഉം വൈഫൈയും"</string>
<string name="profile_name_watch" msgid="576290739483672360">"വാച്ച്"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ഉപയോഗിച്ച് മാനേജ് ചെയ്യുന്നതിന് ഒരു ഉപകരണം തിരഞ്ഞെടുക്കുക"</string>
<string name="chooser_title" msgid="2235819929238267637">"സജ്ജീകരിക്കാൻ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> തിരഞ്ഞെടുക്കുക"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> തിരയുകയാണ്"</string>
<string name="summary_watch" msgid="8134580124808507407">"വിളിക്കുന്നയാളുടെ പേര് പോലുള്ള വിവരങ്ങൾ സമന്വയിപ്പിക്കാനും നിങ്ങളുടെ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> എന്നതിൽ ഈ അനുമതികൾ ആക്സസ് ചെയ്യാനും ഈ ആപ്പിനെ അനുവദിക്കും"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;? മാനേജ് ചെയ്യാൻ, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കുക"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"ഉപകരണം"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml
index 7b0a08ae1aca..e76f68843f59 100644
--- a/packages/CompanionDeviceManager/res/values-mn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-д &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; аппыг хандахыг зөвшөөрөх үү?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Энэ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>-д <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>-г асаасан эсэхийг нягталж, өөрийн <xliff:g id="PROFILE_NAME">%3$s</xliff:g>-г ойр байлгана уу."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Ямар ч төхөөрөмж олдсонгүй. Дараа дахин оролдоно уу."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth, Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"цаг"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-н удирдах төхөөрөмжийг сонгоно уу"</string>
<string name="chooser_title" msgid="2235819929238267637">"Тохируулахын тулд <xliff:g id="PROFILE_NAME">%1$s</xliff:g> сонгоно уу"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g>-г хайж байна"</string>
<string name="summary_watch" msgid="8134580124808507407">"Энэ аппад залгаж буй хэн нэгний нэр зэрэг мэдээллийг синк хийх болон таны <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> дээрх эдгээр зөвшөөрөлд хандахыг зөвшөөрнө"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-г удирдахыг зөвшөөрөх үү?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"төхөөрөмж"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml
index e18f86e5cdfb..722156213623 100644
--- a/packages/CompanionDeviceManager/res/values-mr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"सहयोगी डिव्हाइस व्यवस्थापक"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; अ‍ॅपला &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; अ‍ॅक्सेस करण्याची अनुमती द्यायची आहे का?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"या <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> चे <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> सुरू असल्याची खात्री करा आणि तुमचे<xliff:g id="PROFILE_NAME">%3$s</xliff:g> जवळ ठेवा."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"डिव्हाइस आढळली नाहीत. कृपया नंतर पुन्हा प्रयत्न करा."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"ब्लूटूथ"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"वाय-फाय"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"ब्लूटूथ आणि वाय-फाय"</string>
<string name="profile_name_watch" msgid="576290739483672360">"वॉच"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; द्वारे व्यवस्थापित करण्यासाठी डिव्हाइस निवडा"</string>
<string name="chooser_title" msgid="2235819929238267637">"सेट करण्यासाठी <xliff:g id="PROFILE_NAME">%1$s</xliff:g> निवडा"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> शोधत आहे"</string>
<string name="summary_watch" msgid="8134580124808507407">"या अ‍ॅपला कॉल करत असलेल्या एखाद्या व्यक्तीचे नाव यासारखी माहिती सिंक करण्याची आणि तुमच्या <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> वर पुढील परवानग्या अ‍ॅक्सेस करण्याची अनुमती दिली जाईल"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; व्यवस्थापित करण्याची अनुमती द्यायची आहे?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"डिव्हाइस"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml
index 31cb3b756c6f..ca41c6fe58d2 100644
--- a/packages/CompanionDeviceManager/res/values-ms/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Pengurus Peranti Rakan"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Benarkan apl &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; mengakses &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Pastikan <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> telah dihidupkan pada <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ini dan pastikan <xliff:g id="PROFILE_NAME">%3$s</xliff:g> berada berdekatan."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Tiada peranti ditemukan. Sila cuba sebentar lagi."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth dan Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"jam tangan"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Pilih peranti untuk diurus oleh &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk disediakan"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Mencari <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Apl ini akan dibenarkan untuk menyegerakkan maklumat, seperti nama individu yang membuat panggilan dan mengakses kebenaran ini pada <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> anda"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; mengurus &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"peranti"</string>
diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml
index 0b0273f67aae..f03048bbc997 100644
--- a/packages/CompanionDeviceManager/res/values-my/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-my/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"တွဲဖက်ကိရိယာ မန်နေဂျာ"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကို သုံးရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အက်ပ်ကို ခွင့်ပြုမလား။"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"ဤ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> သည် <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ဖွင့်ထားပြီး သင့် <xliff:g id="PROFILE_NAME">%3$s</xliff:g> အနီးတွင်ရှိကြောင်း သေချာပါစေ။"</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"မည်သည့်စက်မျှ မတွေ့ပါ။ နောက်မှ ထပ်စမ်းကြည့်ပါ။"</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"ဘလူးတုသ်"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"ဘလူးတုသ်၊ Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"နာရီ"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; က စီမံခန့်ခွဲရန် စက်တစ်ခုကို ရွေးပါ"</string>
<string name="chooser_title" msgid="2235819929238267637">"စနစ်ထည့်သွင်းရန် <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ကို ရွေးပါ"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ကို ရှာနေသည်"</string>
<string name="summary_watch" msgid="8134580124808507407">"ခေါ်ဆိုသူ၏အမည်ကဲ့သို့ အချက်အလက်ကို စင့်ခ်လုပ်ရန်နှင့် သင့် <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> တွင် ၎င်းခွင့်ပြုချက်များရယူရန် ဤအက်ပ်ကိုခွင့်ပြုမည်"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကို &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အား စီမံခွင့်ပြုမလား။"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"စက်"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml
index ccb2c572f6f7..1d62349da406 100644
--- a/packages/CompanionDeviceManager/res/values-nb/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Vil du gi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-appen tilgang til &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Sørg for at <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> har <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> slått på, og hold <xliff:g id="PROFILE_NAME">%3$s</xliff:g> i nærheten."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Fant ingen enheter. Prøv på nytt senere."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wifi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth og wifi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"klokke"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Velg en enhet som skal administreres av &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Velg <xliff:g id="PROFILE_NAME">%1$s</xliff:g> som skal konfigureres"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Ser etter en <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Denne appen får tillatelse til å synkronisere informasjon, for eksempel navnet til folk som ringer, og har disse tillatelsene på <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Vil du la &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; administrere &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"enheten"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml
index 203eaeedbd4c..b363c4bdcfbb 100644
--- a/packages/CompanionDeviceManager/res/values-ne/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"सहयोगी डिभाइसको प्रबन्धक"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; एपलाई &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; प्रयोग गर्ने अनुमति दिने हो?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"यो <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> को <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> अन गरिएको छ भन्ने कुरा सुनिश्चित गर्नुहोस् अनि आफ्नो <xliff:g id="PROFILE_NAME">%3$s</xliff:g> नजिकै राख्नुहोस्।"</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"कुनै पनि डिभाइस भेटिएन। कृपया पछि फेरि प्रयास गर्नुहोस्।"</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"ब्लुटुथ"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"ब्लुटुथ तथा Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"घडी"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"आफूले &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; प्रयोग गरी व्यवस्थापन गर्न चाहेको डिभाइस चयन गर्नुहोस्"</string>
<string name="chooser_title" msgid="2235819929238267637">"सेट अप गर्नका लागि <xliff:g id="PROFILE_NAME">%1$s</xliff:g> छनौट गर्नुहोस्"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> खोजिँदै छ"</string>
<string name="summary_watch" msgid="8134580124808507407">"तपाईंको <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> मा यो एपलाई कल गर्ने व्यक्तिको नाम जस्ता जानकारी सिंक गर्ने र यी कुराहरू गर्ने अनुमति दिइने छ"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; व्यवस्थापन गर्ने अनुमति दिने हो?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"डिभाइस"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml
index 069c00c85cfc..5e389611eaa4 100644
--- a/packages/CompanionDeviceManager/res/values-nl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Toestaan dat de app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang heeft tot de &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Zorg dat <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> aanstaat op deze <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> en houd je <xliff:g id="PROFILE_NAME">%3$s</xliff:g> in de buurt."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Geen apparaten gevonden. Probeer het later opnieuw."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wifi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth en wifi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"smartwatch"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Een apparaat kiezen om te beheren met &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Een <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiezen om in te stellen"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Zoeken naar een <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Deze app kan informatie synchroniseren (zoals de naam van iemand die belt) en krijgt toegang tot deze rechten op je <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toestaan &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; te beheren?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"apparaat"</string>
diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml
index a1a6c9023503..14dcc18a532d 100644
--- a/packages/CompanionDeviceManager/res/values-or/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-or/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ସହଯୋଗୀ ଡିଭାଇସ୍ ପରିଚାଳକ"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ଆପକୁ ଅନୁମତି ଦେବେ?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"ସୁନିଶ୍ଚିତ ହୁଏନ୍ତୁ ଏହି <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ରେ <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ଚାଲୁ କରାଯାଇଛି ଏବଂ ଆପଣଙ୍କର <xliff:g id="PROFILE_NAME">%3$s</xliff:g> ଆଖପାଖରେ ରଖନ୍ତୁ।"</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"କୌଣସି ଡିଭାଇସ ମିଳିଲା ନାହିଁ। ଦୟାକରି ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"ବ୍ଲୁଟୁଥ"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"ୱାଇ-ଫାଇ"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"ବ୍ଲୁଟୁଥ ଏବଂ ୱାଇ-ଫାଇ"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ୱାଚ୍"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ଦ୍ୱାରା ପରିଚାଳିତ ହେବା ପାଇଁ ଏକ ଡିଭାଇସ ବାଛନ୍ତୁ"</string>
<string name="chooser_title" msgid="2235819929238267637">"ସେଟ ଅପ କରିବାକୁ ଏକ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ବାଛନ୍ତୁ"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"ଏକ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ଖୋଜୁଛନ୍ତି"</string>
<string name="summary_watch" msgid="8134580124808507407">"କଲ କରୁଥିବା ଯେ କୌଣସି ବ୍ୟକ୍ତିଙ୍କ ନାମ ପରି ସୂଚନା ସିଙ୍କ କରିବାକୁ ଏବଂ ଆପଣଙ୍କ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ରେ ଏହି ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଏହି ଆପକୁ ଅନୁମତି ଦିଆଯିବ"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ପରିଚାଳନା କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଅନୁମତି ଦେବେ?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"ଡିଭାଇସ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml
index cd40ec7a5579..c2db62f88248 100644
--- a/packages/CompanionDeviceManager/res/values-pa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ਸੰਬੰਧੀ ਡੀਵਾਈਸ ਪ੍ਰਬੰਧਕ"</string>
<string name="confirmation_title" msgid="2244241995958340998">"ਕੀ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਐਪ ਨੂੰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"ਪੱਕਾ ਕਰੋ ਕਿ ਇਸ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ਦਾ <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ਚਾਲੂ ਹੋਵੇ ਅਤੇ <xliff:g id="PROFILE_NAME">%3$s</xliff:g> ਨੂੰ ਆਪਣੇ ਨਜ਼ਦੀਕ ਰੱਖੋ।"</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"ਕੋਈ ਡੀਵਾਈਸ ਨਹੀਂ ਮਿਲਿਆ। ਕਿਰਪਾ ਕਰਕੇ ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"ਬਲੂਟੁੱਥ"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"ਵਾਈ-ਫਾਈ"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"ਬਲੂਟੁੱਥ ਅਤੇ ਵਾਈ-ਫਾਈ"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ਸਮਾਰਟ-ਵਾਚ"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤੇ ਜਾਣ ਲਈ ਕੋਈ ਡੀਵਾਈਸ ਚੁਣੋ"</string>
<string name="chooser_title" msgid="2235819929238267637">"ਸੈੱਟਅੱਪ ਕਰਨ ਲਈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ਚੁਣੋ"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ਨੂੰ ਲੱਭਿਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="summary_watch" msgid="8134580124808507407">"ਇਸ ਐਪ ਨੂੰ ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> \'ਤੇ ਕਾਲਰ ਦੇ ਨਾਮ ਵਰਗੀ ਜਾਣਕਾਰੀ ਨੂੰ ਸਿੰਕ ਕਰਨ ਅਤੇ ਇਨ੍ਹਾਂ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਹੋਵੇਗੀ"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"ਕੀ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"ਡੀਵਾਈਸ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index b16776631dfc..90bc1e3bc34b 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Menedżer urządzeń towarzyszących"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Zezwolić aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na dostęp do urządzenia &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Upewnij się, że <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ma włączoną funkcję <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>, i trzymaj urządzenie <xliff:g id="PROFILE_NAME">%3$s</xliff:g> w pobliżu."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nie znaleziono urządzeń. Spróbuj ponownie później."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth i Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"zegarek"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Wybierz urządzenie, którym ma zarządzać aplikacja &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Wybierz profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, aby go skonfigurować"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Szukam: <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Aplikacja będzie mogła synchronizować informacje takie jak nazwa dzwoniącego oraz korzystać z tych uprawnień na Twoim urządzeniu (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Zezwolić na dostęp aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; do urządzenia &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"urządzenie"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
index a6c09d06f143..073fa260c401 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gerenciador de dispositivos complementar"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse o dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Confira se o <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> tem o <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ativado e se o <xliff:g id="PROFILE_NAME">%3$s</xliff:g> está por perto."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nenhum dispositivo foi encontrado. Tente de novo mais tarde."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth e Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Escolha um dispositivo para ser gerenciado pelo app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para configurar"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Procurando um <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"O app poderá sincronizar informações, como o nome de quem está ligando, e acessar estas permissões no seu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gerencie o dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
index 01af6df4f89d..bec6f11edf51 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestor de dispositivos associados"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Permitir que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Certifique-se de que este <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> tem o <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ativado e mantenha o <xliff:g id="PROFILE_NAME">%3$s</xliff:g> próximo."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nenhum dispositivo encontrado. Tente mais tarde."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth e Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Escolha um dispositivo para ser gerido pela app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Escolha um perfil de <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para configurar"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"À procura de um <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Esta app vai poder sincronizar informações, como o nome do autor de uma chamada, e aceder a estas autorizações no seu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça a gestão do dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml
index a6c09d06f143..073fa260c401 100644
--- a/packages/CompanionDeviceManager/res/values-pt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gerenciador de dispositivos complementar"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse o dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Confira se o <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> tem o <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ativado e se o <xliff:g id="PROFILE_NAME">%3$s</xliff:g> está por perto."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nenhum dispositivo foi encontrado. Tente de novo mais tarde."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth e Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Escolha um dispositivo para ser gerenciado pelo app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para configurar"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Procurando um <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"O app poderá sincronizar informações, como o nome de quem está ligando, e acessar estas permissões no seu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gerencie o dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml
index 2b8b5e10b792..40ae72e6f10d 100644
--- a/packages/CompanionDeviceManager/res/values-ro/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Manager de dispozitiv Companion"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Permiți ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să acceseze dispozitivul &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Asigură-te că dispozitivul <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> are activat <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> și ține <xliff:g id="PROFILE_NAME">%3$s</xliff:g> în apropiere."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nu s-au găsit dispozitive. Încearcă din nou mai târziu."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth și Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ceas"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Alege un dispozitiv pe care să îl gestioneze &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Alege un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> de configurat"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Se caută un <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Aplicația va putea să sincronizeze informații, cum ar fi numele unui apelant, și să acceseze aceste permisiuni pe <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Permiți ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să gestioneze &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"dispozitiv"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml
index 605fbd9bbc60..42acfb7a4d36 100644
--- a/packages/CompanionDeviceManager/res/values-ru/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Управление подключенными устройствами"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; доступ к устройству &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Убедитесь, что <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> может устанавливать соединение с другими устройствами по <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> и что нужные настройки включены. Не убирайте <xliff:g id="PROFILE_NAME">%3$s</xliff:g> далеко от него."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Устройства не найдены. Повторите попытку позже."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth и Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"часы"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Выберите устройство, которым будет управлять приложение &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Выберите <xliff:g id="PROFILE_NAME">%1$s</xliff:g> для настройки"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Поиск устройства (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>)"</string>
<string name="summary_watch" msgid="8134580124808507407">"Это приложение сможет синхронизировать данные, например имена звонящих, и получит такие же разрешения на вашем устройстве (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)."</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; управлять устройством &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"устройстве"</string>
diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml
index 63024cac9c25..cc04f4b197c9 100644
--- a/packages/CompanionDeviceManager/res/values-si/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-si/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"සහායක උපාංග කළමනාකරු"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; යෙදුමට &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; වෙත ප්‍රවේශ වීමට ඉඩ දෙන්න ද?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"මෙම <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ක්‍රියාත්මක කර ඇති බවට වග බලා ගන්න, සහ ඔබේ <xliff:g id="PROFILE_NAME">%3$s</xliff:g> ළඟ තබා ගන්න."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"උපාංග හමු නොවිණි. පසුව නැවත උත්සාහ කරන්න."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"බ්ලූටූත්"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"බ්ලූටූත් සහ Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ඔරලෝසුව"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; විසින් කළමනා කරනු ලැබීමට උපාංගයක් තෝරන්න"</string>
<string name="chooser_title" msgid="2235819929238267637">"සැකසීමට <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ක් තෝරන්න"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> සඳහා සොයමින්"</string>
<string name="summary_watch" msgid="8134580124808507407">"මෙම යෙදුමට අමතන කෙනෙකුගේ නම වැනි, තතු සමමුහුර්ත කිරීමට, සහ ඔබේ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> මත මෙම අවසර වෙත ප්‍රවේශ වීමට ඉඩ දෙනු ඇත"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; කළමනා කිරීමට ඉඩ දෙන්න ද?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"උපාංගය"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml
index f80ceca5ead9..9ee2ce574cc0 100644
--- a/packages/CompanionDeviceManager/res/values-sk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Správca sprievodných zariadení"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Chcete povoliť aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prístup k zariadeniu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Uistite sa, že tento typ zariadenia (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) má zapnutú funkciu <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>, a majte <xliff:g id="PROFILE_NAME">%3$s</xliff:g> nablízku."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nenašli sa žiadne zariadenia. Skúste to neskôr."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth a Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Vyberte zariadenie, ktoré bude spravovať aplikácia &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Vyberte profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ktorý nastavíte"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Hľadá sa zariadenie <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Táto aplikácia bude môcť synchronizovať informácie, napríklad meno volajúceho, a získavať prístup k týmto povoleniam v zariadení <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Chcete povoliť aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; spravovať zariadenie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"zariadenie"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml
index 2db2b7861003..3d08276d0e19 100644
--- a/packages/CompanionDeviceManager/res/values-sl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Upravitelj spremljevalnih naprav"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Želite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoliti dostop do naprave &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Poskrbite, da je v napravi <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> vklopljena nastavitev »<xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>«, in napravo <xliff:g id="PROFILE_NAME">%3$s</xliff:g> imejte v bližini."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Ni naprav. Poskusite znova pozneje."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth in Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ura"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Izbira naprave, ki jo bo upravljala aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Izberite profil naprave »<xliff:g id="PROFILE_NAME">%1$s</xliff:g>« za nastavitev"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Iskanje naprave <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Ta aplikacija bo lahko sinhronizirala podatke, na primer ime klicatelja, in dostopala do teh dovoljenj v napravi »<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>«."</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Želite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoliti upravljanje naprave &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"naprava"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml
index 45f008db9594..de3232201da0 100644
--- a/packages/CompanionDeviceManager/res/values-sq/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Menaxheri i pajisjes shoqëruese"</string>
<string name="confirmation_title" msgid="2244241995958340998">"T\'i lejohet aplikacionit &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; qasja te &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Sigurohu që ky <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> të ketë të aktivizuar<xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> dhe mbaje <xliff:g id="PROFILE_NAME">%3$s</xliff:g> tënde pranë."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nuk u gjet asnjë pajisje. Provo përsëri më vonë."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth-in"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth-in dhe Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ora inteligjente"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Zgjidh një pajisje që do të menaxhohet nga &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Zgjidh një <xliff:g id="PROFILE_NAME">%1$s</xliff:g> për konfigurimin"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Po kërkon për një <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Këtij aplikacioni do t\'i lejohet të sinkronizojë informacione, si p.sh. emrin e dikujt që po telefonon, si dhe të ketë qasje në këto leje te <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Të lejohet që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të menaxhojë &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"pajisje"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml
index 650d2d892e90..a86d1e1a5639 100644
--- a/packages/CompanionDeviceManager/res/values-sr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Менаџер придруженог уређаја"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Дозволите да апликација &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; приступа уређају &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Уверите се да је за <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> укључен <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> и да у близини имате <xliff:g id="PROFILE_NAME">%3$s</xliff:g>."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Није пронађен ниједан уређај. Пробајте поново касније."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"WiFi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth и WiFi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"сат"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Одаберите уређај којим ће управљати апликација &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Одаберите профил <xliff:g id="PROFILE_NAME">%1$s</xliff:g> који желите да подесите"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Тражи се <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Овој апликацији ће бити дозвољено да синхронизује податке, попут имена позиваоца, и приступа тим дозволама на уређају <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Желите ли да дозволите да &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; управља уређајем &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"уређај"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml
index d28bff87b674..779079092f50 100644
--- a/packages/CompanionDeviceManager/res/values-sv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Vill du tillåta att appen &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; får åtkomst till &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Se till att <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> har <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> aktiverat och håll <xliff:g id="PROFILE_NAME">%3$s</xliff:g> i närheten."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Inga enheter hittades. Försök igen senare."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wifi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth och wifi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"klocka"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Välj en enhet för hantering av &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Välj en <xliff:g id="PROFILE_NAME">%1$s</xliff:g> för konfigurering"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Söker efter ett <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Appen får synkronisera information, till exempel namnet på någon som ringer, och får åtkomst till dessa behörigheter på din <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Tillåt att &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; hanterar &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"enhet"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml
index afa3ea63b5bf..c0108372a318 100644
--- a/packages/CompanionDeviceManager/res/values-sw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Kidhibiti cha Vifaa Visaidizi"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Ungependa kuruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ifikie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Hakikisha kuwa umewasha <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> kwenye <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> na uweke <xliff:g id="PROFILE_NAME">%3$s</xliff:g> karibu nawe."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Hakuna vifaa vilivyopatikana. Tafadhali jaribu tena baadaye."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth na Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"saa"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Chagua kifaa cha kudhibitiwa na &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Chagua <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ili uweke mipangilio"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Inatafuta <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Programu hii itaruhusiwa kusawazisha maelezo, kama vile jina la mtu anayepiga simu na kufikia ruhusa hizi kwenye <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> yako"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Ungependa kuruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; idhibiti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"kifaa"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml
index fd2038a07dd6..96f7d6310a07 100644
--- a/packages/CompanionDeviceManager/res/values-ta/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"கம்பேனியன் சாதன நிர்வாகி"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; சாதனத்தை அணுக &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"இந்த <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> சாதனத்தின் <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ஆன் செய்யப்பட்டு, அதன் அருகில் உங்கள் <xliff:g id="PROFILE_NAME">%3$s</xliff:g> இருப்பதை உறுதிசெய்துகொள்ளவும்."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"சாதனங்கள் எதுவும் கண்டறியப்படவில்லை. பிறகு முயலவும்."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"புளூடூத்"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"வைஃபை"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"புளூடூத் மற்றும் வைஃபை"</string>
<string name="profile_name_watch" msgid="576290739483672360">"வாட்ச்"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸால் நிர்வகிக்கப்பட வேண்டிய சாதனத்தைத் தேர்வுசெய்யுங்கள்"</string>
<string name="chooser_title" msgid="2235819929238267637">"அமைக்க <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ஐத் தேர்வுசெய்யவும்"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ஐத் தேடுகிறது"</string>
<string name="summary_watch" msgid="8134580124808507407">"அழைப்பவரின் பெயர் போன்ற தகவல்களை ஒத்திசைக்கவும் உங்கள் <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> சாதனத்தில் இந்த அனுமதிகளை அணுகவும் இந்த ஆப்ஸ் அனுமதிக்கப்படும்"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&amp;gt சாதனத்தை நிர்வகிக்க &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"சாதனம்"</string>
diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml
index 8466921f3634..b39b58a39df7 100644
--- a/packages/CompanionDeviceManager/res/values-te/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-te/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"సహచర పరికర మేనేజర్"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;‌ను యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; యాప్‌ను అనుమతించాలా?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"ఈ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>‌లో <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ఆన్‌లో ఉందని నిర్ధారించుకోండి, అలాగే మీ <xliff:g id="PROFILE_NAME">%3$s</xliff:g>‌ను దగ్గరగా ఉంచుకోండి."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"పరికరాలు ఏవీ కనుగొనబడలేదు. దయచేసి తర్వాత మళ్లీ ట్రై చేయండి."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"బ్లూటూత్"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"బ్లూటూత్, Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"వాచ్"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ద్వారా మేనేజ్ చేయబడే పరికరాన్ని ఎంచుకోండి"</string>
<string name="chooser_title" msgid="2235819929238267637">"సెటప్ చేయడానికి <xliff:g id="PROFILE_NAME">%1$s</xliff:g>‌ను ఎంచుకోండి"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> కోసం స్కాన్ చేస్తోంది"</string>
<string name="summary_watch" msgid="8134580124808507407">"కాల్ చేస్తున్న వారి పేరు వంటి సమాచారాన్ని సింక్ చేయడానికి, మీ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>‌లో ఈ అనుమతులను యాక్సెస్ చేయడానికి ఈ యాప్ అనుమతించబడుతుంది"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;‌ను మేనేజ్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;‌ను అనుమతించాలా?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"పరికరం"</string>
diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml
index 2e7ba3c6a37a..6a38c999ee4b 100644
--- a/packages/CompanionDeviceManager/res/values-th/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-th/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"อนุญาตให้แอป &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; เข้าถึง &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ใช่ไหม"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"ตรวจสอบว่า<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>เครื่องนี้เปิด<xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>อยู่ และให้อยู่ใกล้กับ<xliff:g id="PROFILE_NAME">%3$s</xliff:g>"</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"ไม่พบอุปกรณ์ โปรดลองอีกครั้งในภายหลัง"</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"บลูทูธ"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"บลูทูธและ Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"นาฬิกา"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"เลือกอุปกรณ์ที่จะให้มีการจัดการโดย &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"เลือก<xliff:g id="PROFILE_NAME">%1$s</xliff:g>ที่จะตั้งค่า"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"กำลังค้นหา<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"แอปนี้จะได้รับอนุญาตให้ซิงค์ข้อมูล เช่น ชื่อของบุคคลที่โทรเข้ามา และมีสิทธิ์เข้าถึงข้อมูลเหล่านี้ใน<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ของคุณ"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; จัดการ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ไหม"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"อุปกรณ์"</string>
diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml
index 3f4e2af77df9..9150a48fafdd 100644
--- a/packages/CompanionDeviceManager/res/values-tl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Kasamang Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Payagan ang app na &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na i-access ang &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Siguraduhing naka-on ang <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> sa <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> na ito, at panatilihing nasa malapit ang iyong <xliff:g id="PROFILE_NAME">%3$s</xliff:g>."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Walang nakitang device. Pakisubukan ulit sa ibang pagkakataon."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth at Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relo"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Pumili ng device na papamahalaan ng &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Pumili ng <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para mag-set up"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Hinahanap ang <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Papayagan ang app na ito na mag-sync ng impormasyon, tulad ng pangalan ng isang taong tumatawag, at ma-access ang mga pahintulot na ito sa iyong <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na pamahalaan ang &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"device"</string>
diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml
index 3e4603bea751..8ba76bc40653 100644
--- a/packages/CompanionDeviceManager/res/values-tr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazına erişmesi için &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasına izin verin"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Bu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> cihazında <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> özelliğinin etkinleştirildiğinden emin olun ve <xliff:g id="PROFILE_NAME">%3$s</xliff:g> cihazınızı yakında tutun."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Cihaz bulunamadı. Lütfen daha sonra tekrar deneyin."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Kablosuz"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth ve Kablosuz"</string>
<string name="profile_name_watch" msgid="576290739483672360">"saat"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tarafından yönetilecek bir cihaz seçin"</string>
<string name="chooser_title" msgid="2235819929238267637">"Ayarlamak için bir <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> aranıyor"</string>
<string name="summary_watch" msgid="8134580124808507407">"Bu uygulamanın arayan kişinin adı gibi bilgileri senkronize etmesine ve <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> cihazınızda aşağıdaki izinlere erişmesine izin verilir"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasına &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazını yönetmesi için izin verilsin mi?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"Cihaz"</string>
diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml
index 18adf00c8c5b..ff93a657455d 100644
--- a/packages/CompanionDeviceManager/res/values-uk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Диспетчер супутніх пристроїв"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Дозволити додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; доступ до інформації на пристрої &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Перевірте цей <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> і переконайтеся, що на ньому ввімкнено <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>, а тоді тримайте <xliff:g id="PROFILE_NAME">%3$s</xliff:g> поблизу."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Пристрої не знайдено. Повторіть спробу пізніше."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth і Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"годинник"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Виберіть пристрій, яким керуватиме додаток &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Виберіть <xliff:g id="PROFILE_NAME">%1$s</xliff:g> для налаштування"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Шукаємо <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Цей додаток зможе синхронізувати інформацію (наприклад, ім’я абонента, який викликає) і отримає доступ до перелічених нижче дозволів на вашому <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Дозволити додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; керувати пристроєм &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"пристрій"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml
index cb1a5278dfc1..e502a792d23b 100644
--- a/packages/CompanionDeviceManager/res/values-ur/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ساتھی آلہ مینیجر"</string>
<string name="confirmation_title" msgid="2244241995958340998">"‏ایپ ‎&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>‎&lt;/strong&gt;‎ کو ‎‎&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;‎ تک رسائی کی اجازت دیں؟"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"یقینی بنائیں کہ اس <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> کا <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> آن ہے اور اپنی <xliff:g id="PROFILE_NAME">%3$s</xliff:g> کو قریب رکھیں۔"</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"کوئی آلہ نہیں ملا۔ براہ کرم بعد میں دوبارہ کوشش کریں۔"</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"بلوٹوتھ"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"‏بلوٹوتھ اور Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"دیکھیں"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"‏‎&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;‎ کے ذریعے منتخب کیے جانے کیلئے آلہ منتخب کریں"</string>
<string name="chooser_title" msgid="2235819929238267637">"سیٹ اپ کرنے کے لیے <xliff:g id="PROFILE_NAME">%1$s</xliff:g> کا انتخاب کریں"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"‫<xliff:g id="PROFILE_NAME">%1$s</xliff:g> کو تلاش کیا جا رہا ہے"</string>
<string name="summary_watch" msgid="8134580124808507407">"اس ایپ کو آپ کے <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> پر کسی کال کرنے والے کے نام جیسی معلومات کی مطابقت پذیری کرنے اور ان اجازتوں تک رسائی کی اجازت ہوگی"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"‏&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; کا نظم کرنے کی اجازت دیں؟"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"آلہ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml
index 993c50226103..076bb74d6bf6 100644
--- a/packages/CompanionDeviceManager/res/values-uz/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qurilmasidan foydalanishga ruxsat berilsinmi?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Bu <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>da <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> yoqilganini tekshiring va <xliff:g id="PROFILE_NAME">%3$s</xliff:g>ni tayyor tuting."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Hech qanday qurilma topilmadi. Keyinroq qayta urining."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth va Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"soat"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; boshqaradigan qurilmani tanlang"</string>
<string name="chooser_title" msgid="2235819929238267637">"Sozlash uchun <xliff:g id="PROFILE_NAME">%1$s</xliff:g> profilini tanlang"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> qidirilmoqda"</string>
<string name="summary_watch" msgid="8134580124808507407">"Bu ilovaga chaqiruvchining ismi kabi maʼlumotlarni sinxronlash va <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> qurilmasida quyidagi amallarni bajarishga ruxsat beriladi"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qurilmasini boshqarish uchun ruxsat berilsinmi?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"qurilma"</string>
diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml
index dee65de16b73..a44af74b1182 100644
--- a/packages/CompanionDeviceManager/res/values-vi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Trình quản lý thiết bị đồng hành"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Cho phép ứng dụng &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập vào &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Hãy đảm bảo rằng <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> này đã bật <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> và được đặt gần <xliff:g id="PROFILE_NAME">%3$s</xliff:g> của bạn."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Không tìm thấy thiết bị nào. Vui lòng thử lại sau."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth và Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"đồng hồ"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Chọn một thiết bị sẽ do &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; quản lý"</string>
<string name="chooser_title" msgid="2235819929238267637">"Chọn một <xliff:g id="PROFILE_NAME">%1$s</xliff:g> để thiết lập"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Đang tìm <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Ứng dụng này sẽ được phép đồng bộ hoá thông tin (chẳng hạn như tên của người đang gọi điện) và dùng những quyền sau trên <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> của bạn"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; quản lý &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"thiết bị"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
index 605cab7185d8..4360092564ea 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"配套设备管理器"</string>
<string name="confirmation_title" msgid="2244241995958340998">"允许应用&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;访问&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"请确保此<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>已开启<xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>,并将<xliff:g id="PROFILE_NAME">%3$s</xliff:g>放在附近。"</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"找不到设备,请稍后重试。"</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"蓝牙"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"WLAN"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"蓝牙和 WLAN"</string>
<string name="profile_name_watch" msgid="576290739483672360">"手表"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"选择要由&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;管理的设备"</string>
<string name="chooser_title" msgid="2235819929238267637">"选择 <xliff:g id="PROFILE_NAME">%1$s</xliff:g> 进行设置"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"寻找<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"该应用将能同步信息(例如来电者的姓名),并能获得您<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>上的以下权限"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"允许&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;管理&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"设备"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
index d1c73e538981..3dcaa9f7e5d6 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"隨附裝置管理工具"</string>
<string name="confirmation_title" msgid="2244241995958340998">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」應用程式&lt;strong&gt;&lt;/strong&gt;存取「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;嗎?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"請確保你已開啟此<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>的<xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>,並將<xliff:g id="PROFILE_NAME">%3$s</xliff:g>放在附近。"</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"找不到任何裝置,請稍後再試。"</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"藍牙"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"藍牙和 Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"選擇要讓 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 管理的裝置"</string>
<string name="chooser_title" msgid="2235819929238267637">"選擇要設定的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"正在搜尋<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"此應用程式將可同步資訊 (例如來電者的名稱),並可在<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>上取得以下權限"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;管理「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;嗎?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"裝置"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
index c675fedb1dbd..2bfcaf296420 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"隨附裝置管理工具"</string>
<string name="confirmation_title" msgid="2244241995958340998">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;應用程式存取「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;嗎?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"請確認這個<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>已開啟<xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>,並將<xliff:g id="PROFILE_NAME">%3$s</xliff:g>放在附近。"</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"找不到裝置,請稍後再試。"</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"藍牙"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"藍牙和 Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"選擇要讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;管理的裝置"</string>
<string name="chooser_title" msgid="2235819929238267637">"選擇要設定的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"尋找<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"這個應用程式將可同步處理資訊 (例如來電者名稱) 及取得<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>上的這些權限"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;管理「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;嗎?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"裝置"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml
index 365b2f4753d0..bc7bb819b1c1 100644
--- a/packages/CompanionDeviceManager/res/values-zu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml
@@ -18,9 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Isiphathi sedivayisi esihambisanayo"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Vumela i-app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukufinyelela &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Qinisekisa ukuthi le-<xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ivule i-<xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>, futhi ugcine i-<xliff:g id="PROFILE_NAME">%3$s</xliff:g> yakho iseduze."</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"Awekho amadivayisi atholiwe. Sicela uzame futhi kamuva."</string>
+ <string name="discovery_bluetooth" msgid="5693557668470016164">"IBluetooth"</string>
+ <string name="discovery_wifi" msgid="1551782459721758773">"I-Wi-Fi"</string>
+ <string name="discovery_mixed" msgid="7071466134150760127">"IBluetooth ne-Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"buka"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Khetha idivayisi engaphathwa nge-&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Khetha i-<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ukusetha"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Ufuna i-<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Le app izovunyelwa ukuvumelanisa ulwazi, olufana negama lomuntu ofonayo, iphinde ifinyelele lezi zimvume ku-<xliff:g id="DEVICE_TYPE">%1$s</xliff:g> yakho"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Vumela i-&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukuthi ifinyelele i-&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"idivayisi"</string>
diff --git a/packages/CrashRecovery/framework/Android.bp b/packages/CrashRecovery/framework/Android.bp
index 1a3446ec56de..5dd42bb633e5 100644
--- a/packages/CrashRecovery/framework/Android.bp
+++ b/packages/CrashRecovery/framework/Android.bp
@@ -1,8 +1,8 @@
filegroup {
name: "framework-crashrecovery-sources",
srcs: [
- "java/**/*.java",
"java/**/*.aidl",
+ "java/**/*.java",
],
path: "java",
visibility: [
@@ -12,11 +12,14 @@ filegroup {
java_sdk_library {
name: "framework-platformcrashrecovery",
- srcs: [":framework-crashrecovery-sources"],
+ srcs: [
+ ":framework-crashrecovery-module-sources",
+ ":framework-crashrecovery-sources",
+ ],
defaults: ["framework-non-updatable-unbundled-defaults"],
permitted_packages: [
- "android.service.watchdog",
"android.crashrecovery",
+ "android.service.watchdog",
],
static_libs: ["android.crashrecovery.flags-aconfig-java"],
aidl: {
diff --git a/packages/CrashRecovery/services/module/java/com/android/server/RescueParty.java b/packages/CrashRecovery/services/module/java/com/android/server/RescueParty.java
index 40bc5f78a9c6..846da194b3c3 100644
--- a/packages/CrashRecovery/services/module/java/com/android/server/RescueParty.java
+++ b/packages/CrashRecovery/services/module/java/com/android/server/RescueParty.java
@@ -29,18 +29,13 @@ import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.crashrecovery.flags.Flags;
import android.os.Build;
-import android.os.Environment;
import android.os.PowerManager;
import android.os.RecoverySystem;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.provider.DeviceConfig;
import android.provider.Settings;
import android.sysprop.CrashRecoveryProperties;
import android.text.TextUtils;
-import android.util.ArraySet;
-import android.util.ArrayUtils;
import android.util.EventLog;
import android.util.FileUtils;
import android.util.Log;
@@ -56,10 +51,7 @@ import com.android.server.crashrecovery.proto.CrashRecoveryStatsLog;
import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@@ -241,87 +233,11 @@ public class RescueParty {
CrashRecoveryProperties.maxRescueLevelAttempted(level);
}
- private static Set<String> getPresetNamespacesForPackages(List<String> packageNames) {
- Set<String> resultSet = new ArraySet<String>();
- if (!Flags.deprecateFlagsAndSettingsResets()) {
- try {
- String flagVal = DeviceConfig.getString(NAMESPACE_CONFIGURATION,
- NAMESPACE_TO_PACKAGE_MAPPING_FLAG, "");
- String[] mappingEntries = flagVal.split(",");
- for (int i = 0; i < mappingEntries.length; i++) {
- if (TextUtils.isEmpty(mappingEntries[i])) {
- continue;
- }
- String[] splitEntry = mappingEntries[i].split(":");
- if (splitEntry.length != 2) {
- throw new RuntimeException("Invalid mapping entry: " + mappingEntries[i]);
- }
- String namespace = splitEntry[0];
- String packageName = splitEntry[1];
-
- if (packageNames.contains(packageName)) {
- resultSet.add(namespace);
- }
- }
- } catch (Exception e) {
- resultSet.clear();
- Slog.e(TAG, "Failed to read preset package to namespaces mapping.", e);
- } finally {
- return resultSet;
- }
- } else {
- return resultSet;
- }
- }
-
@VisibleForTesting
static long getElapsedRealtime() {
return SystemClock.elapsedRealtime();
}
- private static class RescuePartyMonitorCallback implements DeviceConfig.MonitorCallback {
- Context mContext;
-
- RescuePartyMonitorCallback(Context context) {
- this.mContext = context;
- }
-
- public void onNamespaceUpdate(@NonNull String updatedNamespace) {
- if (!Flags.deprecateFlagsAndSettingsResets()) {
- startObservingPackages(mContext, updatedNamespace);
- }
- }
-
- public void onDeviceConfigAccess(@NonNull String callingPackage,
- @NonNull String namespace) {
-
- if (!Flags.deprecateFlagsAndSettingsResets()) {
- RescuePartyObserver.getInstance(mContext).recordDeviceConfigAccess(
- callingPackage,
- namespace);
- }
- }
- }
-
- private static void startObservingPackages(Context context, @NonNull String updatedNamespace) {
- if (!Flags.deprecateFlagsAndSettingsResets()) {
- RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context);
- Set<String> callingPackages = rescuePartyObserver.getCallingPackagesSet(
- updatedNamespace);
- if (callingPackages == null) {
- return;
- }
- List<String> callingPackageList = new ArrayList<>();
- callingPackageList.addAll(callingPackages);
- Slog.i(TAG, "Starting to observe: " + callingPackageList + ", updated namespace: "
- + updatedNamespace);
- PackageWatchdog.getInstance(context).startExplicitHealthCheck(
- callingPackageList,
- DEFAULT_OBSERVING_DURATION_MS,
- rescuePartyObserver);
- }
- }
-
private static int getMaxRescueLevel(boolean mayPerformReboot) {
if (Flags.recoverabilityDetection()) {
if (!mayPerformReboot
@@ -849,34 +765,6 @@ public class RescueParty {
}
}
- private synchronized void recordDeviceConfigAccess(@NonNull String callingPackage,
- @NonNull String namespace) {
- if (!Flags.deprecateFlagsAndSettingsResets()) {
- // Record it in calling packages to namespace map
- Set<String> namespaceSet = mCallingPackageNamespaceSetMap.get(callingPackage);
- if (namespaceSet == null) {
- namespaceSet = new ArraySet<>();
- mCallingPackageNamespaceSetMap.put(callingPackage, namespaceSet);
- }
- namespaceSet.add(namespace);
- // Record it in namespace to calling packages map
- Set<String> callingPackageSet = mNamespaceCallingPackageSetMap.get(namespace);
- if (callingPackageSet == null) {
- callingPackageSet = new ArraySet<>();
- }
- callingPackageSet.add(callingPackage);
- mNamespaceCallingPackageSetMap.put(namespace, callingPackageSet);
- }
- }
-
- private synchronized Set<String> getAffectedNamespaceSet(String failedPackage) {
- return mCallingPackageNamespaceSetMap.get(failedPackage);
- }
-
- private synchronized Set<String> getAllAffectedNamespaceSet() {
- return new HashSet<String>(mNamespaceCallingPackageSetMap.keySet());
- }
-
private synchronized Set<String> getCallingPackagesSet(String namespace) {
return mNamespaceCallingPackageSetMap.get(namespace);
}
@@ -894,26 +782,6 @@ public class RescueParty {
return now < lastResetTime + TimeUnit.MINUTES.toMillis(throttleDurationMin);
}
- private static int[] getAllUserIds() {
- int systemUserId = UserHandle.SYSTEM.getIdentifier();
- int[] userIds = { systemUserId };
- try {
- for (File file : FileUtils.listFilesOrEmpty(
- Environment.getDataSystemDeviceProtectedDirectory())) {
- try {
- final int userId = Integer.parseInt(file.getName());
- if (userId != systemUserId) {
- userIds = ArrayUtils.appendInt(userIds, userId);
- }
- } catch (NumberFormatException ignored) {
- }
- }
- } catch (Throwable t) {
- Slog.w(TAG, "Trouble discovering users", t);
- }
- return userIds;
- }
-
/**
* Hacky test to check if the device has an active USB connection, which is
* a good proxy for someone doing local development work.
diff --git a/packages/CrashRecovery/services/module/java/com/android/util/ArrayUtils.java b/packages/CrashRecovery/services/module/java/com/android/util/ArrayUtils.java
index 0b7b98603419..29ff7cced897 100644
--- a/packages/CrashRecovery/services/module/java/com/android/util/ArrayUtils.java
+++ b/packages/CrashRecovery/services/module/java/com/android/util/ArrayUtils.java
@@ -16,13 +16,8 @@
package android.util;
-import android.annotation.NonNull;
import android.annotation.Nullable;
-import java.io.File;
-import java.util.List;
-import java.util.Objects;
-
/**
* Copied over from frameworks/base/core/java/com/android/internal/util/ArrayUtils.java
*
@@ -30,25 +25,6 @@ import java.util.Objects;
*/
public class ArrayUtils {
private ArrayUtils() { /* cannot be instantiated */ }
- public static final File[] EMPTY_FILE = new File[0];
-
-
- /**
- * Return first index of {@code value} in {@code array}, or {@code -1} if
- * not found.
- */
- public static <T> int indexOf(@Nullable T[] array, T value) {
- if (array == null) return -1;
- for (int i = 0; i < array.length; i++) {
- if (Objects.equals(array[i], value)) return i;
- }
- return -1;
- }
-
- /** @hide */
- public static @NonNull File[] defeatNullable(@Nullable File[] val) {
- return (val != null) ? val : EMPTY_FILE;
- }
/**
* Checks if given array is null or has zero elements.
@@ -63,53 +39,4 @@ public class ArrayUtils {
public static boolean isEmpty(@Nullable byte[] array) {
return array == null || array.length == 0;
}
-
- /**
- * Converts from List of bytes to byte array
- * @param list
- * @return byte[]
- */
- public static byte[] toPrimitive(List<byte[]> list) {
- if (list.size() == 0) {
- return new byte[0];
- }
- int byteLen = list.get(0).length;
- byte[] array = new byte[list.size() * byteLen];
- for (int i = 0; i < list.size(); i++) {
- for (int j = 0; j < list.get(i).length; j++) {
- array[i * byteLen + j] = list.get(i)[j];
- }
- }
- return array;
- }
-
- /**
- * Adds value to given array if not already present, providing set-like
- * behavior.
- */
- public static @NonNull int[] appendInt(@Nullable int[] cur, int val) {
- return appendInt(cur, val, false);
- }
-
- /**
- * Adds value to given array.
- */
- public static @NonNull int[] appendInt(@Nullable int[] cur, int val,
- boolean allowDuplicates) {
- if (cur == null) {
- return new int[] { val };
- }
- final int n = cur.length;
- if (!allowDuplicates) {
- for (int i = 0; i < n; i++) {
- if (cur[i] == val) {
- return cur;
- }
- }
- }
- int[] ret = new int[n + 1];
- System.arraycopy(cur, 0, ret, 0, n);
- ret[n] = val;
- return ret;
- }
}
diff --git a/packages/CrashRecovery/services/module/java/com/android/util/FileUtils.java b/packages/CrashRecovery/services/module/java/com/android/util/FileUtils.java
index 9c73feeffb6c..d60a9b9847ca 100644
--- a/packages/CrashRecovery/services/module/java/com/android/util/FileUtils.java
+++ b/packages/CrashRecovery/services/module/java/com/android/util/FileUtils.java
@@ -16,7 +16,6 @@
package android.util;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import java.io.BufferedInputStream;
@@ -115,14 +114,4 @@ public class FileUtils {
}
return false;
}
-
- /**
- * List the files in the directory or return empty file.
- *
- * @hide
- */
- public static @NonNull File[] listFilesOrEmpty(@Nullable File dir) {
- return (dir != null) ? ArrayUtils.defeatNullable(dir.listFiles())
- : ArrayUtils.EMPTY_FILE;
- }
}
diff --git a/packages/CrashRecovery/services/module/java/com/android/util/XmlUtils.java b/packages/CrashRecovery/services/module/java/com/android/util/XmlUtils.java
index 50823f5c9c34..488b531c2b8a 100644
--- a/packages/CrashRecovery/services/module/java/com/android/util/XmlUtils.java
+++ b/packages/CrashRecovery/services/module/java/com/android/util/XmlUtils.java
@@ -16,21 +16,10 @@
package android.util;
-import android.annotation.NonNull;
-import android.system.ErrnoException;
-import android.system.Os;
-
-import com.android.modules.utils.TypedXmlPullParser;
-
-import libcore.util.XmlObjectFactory;
-
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import java.io.BufferedInputStream;
-import java.io.FileInputStream;
import java.io.IOException;
-import java.io.InputStream;
/**
* Bits and pieces copied from hidden API of
@@ -40,8 +29,6 @@ import java.io.InputStream;
*/
public class XmlUtils {
- private static final String STRING_ARRAY_SEPARATOR = ":";
-
/** @hide */
public static final void beginDocument(XmlPullParser parser, String firstElementName)
throws XmlPullParserException, IOException {
@@ -76,44 +63,4 @@ public class XmlUtils {
}
}
}
-
- private static XmlPullParser newPullParser() {
- try {
- XmlPullParser parser = XmlObjectFactory.newXmlPullParser();
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_DOCDECL, true);
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- return parser;
- } catch (XmlPullParserException e) {
- throw new AssertionError();
- }
- }
-
- /** @hide */
- public static @NonNull TypedXmlPullParser resolvePullParser(@NonNull InputStream in)
- throws IOException {
- final byte[] magic = new byte[4];
- if (in instanceof FileInputStream) {
- try {
- Os.pread(((FileInputStream) in).getFD(), magic, 0, magic.length, 0);
- } catch (ErrnoException e) {
- throw e.rethrowAsIOException();
- }
- } else {
- if (!in.markSupported()) {
- in = new BufferedInputStream(in);
- }
- in.mark(8);
- in.read(magic);
- in.reset();
- }
-
- final TypedXmlPullParser xml;
- xml = (TypedXmlPullParser) newPullParser();
- try {
- xml.setInput(in, "UTF_8");
- } catch (XmlPullParserException e) {
- throw new IOException(e);
- }
- return xml;
- }
}
diff --git a/packages/CredentialManager/res/values-eu/strings.xml b/packages/CredentialManager/res/values-eu/strings.xml
index 66ad31b3927c..0ef3a8fe9ffc 100644
--- a/packages/CredentialManager/res/values-eu/strings.xml
+++ b/packages/CredentialManager/res/values-eu/strings.xml
@@ -72,7 +72,7 @@
<string name="get_dialog_title_use_password_for" msgid="688557784207167647">"Erabili <xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako gordetako pasahitza"</string>
<string name="get_dialog_title_use_sign_in_for" msgid="4233553937542583226">"Erabili zure kontua <xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako"</string>
<string name="get_dialog_description_single_tap" msgid="2797059565126030879">"Erabili pantailaren blokeoa <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioan <xliff:g id="USERNAME">%2$s</xliff:g> kontuarekin saioa hasteko"</string>
- <string name="get_dialog_title_unlock_options_for" msgid="7096423827682163270">"Desblokeatu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioan saioa hasteko aukerak"</string>
+ <string name="get_dialog_title_unlock_options_for" msgid="7096423827682163270">"Desblokeatu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioan saioa hasteko moduak"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Aukeratu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako gordetako sarbide-gakoa"</string>
<string name="get_dialog_title_choose_password_for" msgid="1724435823820819221">"Aukeratu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako gordetako pasahitza"</string>
<string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"Aukeratu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako gordetako saioa hasteko moduak"</string>
@@ -82,7 +82,7 @@
<string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Hasi saioa beste modu batean"</string>
<string name="snackbar_action" msgid="37373514216505085">"Ikusi aukerak"</string>
<string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Egin aurrera"</string>
- <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Saioa hasteko aukerak"</string>
+ <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Saioa hasteko moduak"</string>
<string name="button_label_view_more" msgid="3429098227286495651">"Ikusi gehiago"</string>
<string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> erabiltzailearenak"</string>
<string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Blokeatutako pasahitz-kudeatzaileak"</string>
diff --git a/packages/CredentialManager/res/values-iw/strings.xml b/packages/CredentialManager/res/values-iw/strings.xml
index 51f163922203..7f944b4c3310 100644
--- a/packages/CredentialManager/res/values-iw/strings.xml
+++ b/packages/CredentialManager/res/values-iw/strings.xml
@@ -86,7 +86,7 @@
<string name="button_label_view_more" msgid="3429098227286495651">"עוד מידע"</string>
<string name="get_dialog_heading_for_username" msgid="3456868514554204776">"עבור <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
<string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"מנהלי סיסמאות נעולים"</string>
- <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"יש להקיש כדי לבטל את הנעילה"</string>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"יש ללחוץ כדי לבטל את הנעילה"</string>
<string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"אין פרטי כניסה"</string>
<string name="no_sign_in_info_in" msgid="2641118151920288356">"אין פרטי כניסה ב-<xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"ניהול כניסות"</string>
diff --git a/packages/CredentialManager/wear/res/values-iw/strings.xml b/packages/CredentialManager/wear/res/values-iw/strings.xml
index 4fb203d43386..bc9e180e79fe 100644
--- a/packages/CredentialManager/wear/res/values-iw/strings.xml
+++ b/packages/CredentialManager/wear/res/values-iw/strings.xml
@@ -30,5 +30,5 @@
<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>
+ <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="4320941096211904568">"צריך ללחוץ כדי לבטל את הנעילה"</string>
</resources>
diff --git a/packages/EasterEgg/AndroidManifest.xml b/packages/EasterEgg/AndroidManifest.xml
index 754abb2f76be..96e5892f4d1d 100644
--- a/packages/EasterEgg/AndroidManifest.xml
+++ b/packages/EasterEgg/AndroidManifest.xml
@@ -33,7 +33,7 @@
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application
- android:icon="@drawable/android15_patch_adaptive"
+ android:icon="@drawable/android16_patch_adaptive"
android:label="@string/app_name">
<!-- Android V easter egg: Daydream version of Landroid
@@ -41,7 +41,7 @@
<service
android:name=".landroid.DreamUniverse"
android:exported="true"
- android:icon="@drawable/android15_patch_adaptive"
+ android:icon="@drawable/android16_patch_adaptive"
android:label="@string/v_egg_name"
android:description="@string/dream_description"
android:enabled="false"
@@ -62,7 +62,7 @@
android:name=".landroid.MainActivity"
android:exported="true"
android:label="@string/u_egg_name"
- android:icon="@drawable/android15_patch_adaptive"
+ android:icon="@drawable/android16_patch_adaptive"
android:configChanges="orientation|screenLayout|screenSize|density"
android:theme="@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen">
<intent-filter>
diff --git a/packages/EasterEgg/res/drawable/android16_patch_adaptive.xml b/packages/EasterEgg/res/drawable/android16_patch_adaptive.xml
new file mode 100644
index 000000000000..277df47438e3
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android16_patch_adaptive.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.
+-->
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/android16_patch_adaptive_background"/>
+ <foreground android:drawable="@drawable/android16_patch_adaptive_foreground"/>
+ <monochrome android:drawable="@drawable/android16_patch_monochrome"/>
+</adaptive-icon>
diff --git a/packages/EasterEgg/res/drawable/android16_patch_adaptive_background.xml b/packages/EasterEgg/res/drawable/android16_patch_adaptive_background.xml
new file mode 100644
index 000000000000..17c2b927f4fd
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android16_patch_adaptive_background.xml
@@ -0,0 +1,245 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <group>
+ <clip-path
+ android:pathData="M0,0h108v108h-108z"/>
+ <path
+ android:pathData="M73,54L54,35L35,54L54,73L73,54Z"
+ android:fillColor="#34A853"/>
+ <path
+ android:pathData="M44.5,44.5L54,44.5L44.5,54L44.5,44.5Z"
+ android:fillColor="#1F8E3D"/>
+ <path
+ android:pathData="M63.5,63.5L54,63.5L63.5,54L63.5,63.5Z"
+ android:fillColor="#1F8E3D"/>
+ <path
+ android:pathData="M54,54L54,44.5L63.5,54L54,54Z"
+ android:fillColor="#1F8E3D"/>
+ <path
+ android:pathData="M54,44.5L54,35L63.5,44.5L54,44.5Z"
+ android:fillColor="#1F8E3D"/>
+ <path
+ android:pathData="M54,63.5L54,73L44.5,63.5L54,63.5Z"
+ android:fillColor="#1F8E3D"/>
+ <path
+ android:pathData="M63.5,54L63.5,44.5L73,54L63.5,54Z"
+ android:fillColor="#1F8E3D"/>
+ <path
+ android:pathData="M44.5,54L44.5,63.5L35,54L44.5,54Z"
+ android:fillColor="#1F8E3D"/>
+ <path
+ android:pathData="M54,54L54,63.5L44.5,54L54,54Z"
+ android:fillColor="#1F8E3D"/>
+ <path
+ android:pathData="M82.5,25.5L82.5,35L73,25.5L82.5,25.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M63.5,44.5L63.5,35L73,44.5L63.5,44.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M73,35L82.5,35L73,44.5L73,35Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M82.5,35L92,35L82.5,44.5L82.5,35Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M63.5,35L54,35L63.5,25.5L63.5,35Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M73,44.5L82.5,44.5L73,54L73,44.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M73,25.5L63.5,25.5L73,16L73,25.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M73,35L63.5,35L73,25.5L73,35Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M82.5,63.5L82.5,73L73,63.5L82.5,63.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M63.5,82.5L63.5,73L73,82.5L63.5,82.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M73,73L82.5,73L73,82.5L73,73Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M82.5,73L92,73L82.5,82.5L82.5,73Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M63.5,73L54,73L63.5,63.5L63.5,73Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M73,82.5L82.5,82.5L73,92L73,82.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M73,63.5L63.5,63.5L73,54L73,63.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M73,73L63.5,73L73,63.5L73,73Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M44.5,63.5L44.5,73L35,63.5L44.5,63.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M25.5,82.5L25.5,73L35,82.5L25.5,82.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M35,73L44.5,73L35,82.5L35,73Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M44.5,73L54,73L44.5,82.5L44.5,73Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M25.5,73L16,73L25.5,63.5L25.5,73Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M35,82.5L44.5,82.5L35,92L35,82.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M35,63.5L25.5,63.5L35,54L35,63.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M35,73L25.5,73L35,63.5L35,73Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M44.5,25.5L44.5,35L35,25.5L44.5,25.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M25.5,44.5L25.5,35L35,44.5L25.5,44.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M35,35L44.5,35L35,44.5L35,35Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M44.5,35L54,35L44.5,44.5L44.5,35Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M25.5,35L16,35L25.5,25.5L25.5,35Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M35,44.5L44.5,44.5L35,54L35,44.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M35,25.5L25.5,25.5L35,16L35,25.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M35,35L25.5,35L35,25.5L35,35Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M63.5,25.5L54,25.5L63.5,16L63.5,25.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M44.5,6.5L54,6.5L44.5,16L44.5,6.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M54,16L54,25.5L44.5,16L54,16Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M54,25.5L54,35L44.5,25.5L54,25.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M54,6.5L54,-3L63.5,6.5L54,6.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M44.5,16L44.5,25.5L35,16L44.5,16Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M63.5,16L63.5,6.5L73,16L63.5,16Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M54,16L54,6.5L63.5,16L54,16Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M101.5,63.5L92,63.5L101.5,54L101.5,63.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M82.5,44.5L92,44.5L82.5,54L82.5,44.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M92,54L92,63.5L82.5,54L92,54Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M92,63.5L92,73L82.5,63.5L92,63.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M92,44.5L92,35L101.5,44.5L92,44.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M82.5,54L82.5,63.5L73,54L82.5,54Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M101.5,54L101.5,44.5L111,54L101.5,54Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M92,54L92,44.5L101.5,54L92,54Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M63.5,101.5L54,101.5L63.5,92L63.5,101.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M44.5,82.5L54,82.5L44.5,92L44.5,82.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M54,92L54,101.5L44.5,92L54,92Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M54,101.5L54,111L44.5,101.5L54,101.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M54,82.5L54,73L63.5,82.5L54,82.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M44.5,92L44.5,101.5L35,92L44.5,92Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M63.5,92L63.5,82.5L73,92L63.5,92Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M54,92L54,82.5L63.5,92L54,92Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M25.5,63.5L16,63.5L25.5,54L25.5,63.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M6.5,44.5L16,44.5L6.5,54L6.5,44.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M16,54L16,63.5L6.5,54L16,54Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M16,63.5L16,73L6.5,63.5L16,63.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M16,44.5L16,35L25.5,44.5L16,44.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M6.5,54L6.5,63.5L-3,54L6.5,54Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M25.5,54L25.5,44.5L35,54L25.5,54Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M16,54L16,44.5L25.5,54L16,54Z"
+ android:fillColor="#16161D"/>
+ </group>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/android16_patch_adaptive_foreground.xml b/packages/EasterEgg/res/drawable/android16_patch_adaptive_foreground.xml
new file mode 100644
index 000000000000..4c2932399c1a
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android16_patch_adaptive_foreground.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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:pathData="M40.65,63.013C40.722,62.922 40.716,62.789 40.633,62.707V62.707C40.537,62.61 40.377,62.62 40.292,62.727C34.567,69.881 31.569,75.536 33.089,77.056C35.366,79.333 46.923,71.469 58.901,59.491C60.049,58.343 61.159,57.199 62.226,56.066C62.342,55.943 62.339,55.751 62.219,55.632L61.566,54.978C61.441,54.854 61.238,54.857 61.117,54.985C60.057,56.11 58.951,57.25 57.806,58.395C46.882,69.319 36.496,76.646 34.61,74.759C33.417,73.567 35.903,68.982 40.65,63.013Z"
+ android:fillColor="#C6FF00"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M67.956,52.033C68.205,51.966 68.462,52.115 68.529,52.364C68.596,52.614 68.448,52.871 68.198,52.938L67.956,52.033ZM68.198,52.938L63.926,54.083L63.683,53.178L67.956,52.033L68.198,52.938Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M64.497,49.237C64.564,48.987 64.821,48.839 65.071,48.906C65.32,48.973 65.469,49.229 65.402,49.479L64.497,49.237ZM65.402,49.479L64.257,53.752L63.352,53.509L64.497,49.237L65.402,49.479Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M66.145,51.236C64.869,49.961 62.83,49.931 61.591,51.17L58.825,53.937C58.585,54.176 58.585,54.564 58.825,54.803C59.063,55.042 59.452,55.042 59.691,54.803L60.436,54.057C60.915,53.579 61.69,53.579 62.169,54.057L63.324,55.212C63.802,55.691 63.802,56.466 63.324,56.945L62.578,57.69C62.339,57.929 62.339,58.318 62.578,58.557C62.817,58.796 63.205,58.796 63.444,58.557L66.211,55.79C67.45,54.551 67.42,52.512 66.145,51.236Z"
+ android:fillColor="#000000"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/android16_patch_monochrome.xml b/packages/EasterEgg/res/drawable/android16_patch_monochrome.xml
new file mode 100644
index 000000000000..608d5ea6ee48
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android16_patch_monochrome.xml
@@ -0,0 +1,113 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:strokeWidth="1"
+ android:pathData="M54.707,35.707L72.293,53.293A1,1 102.155,0 1,72.293 54.707L54.707,72.293A1,1 0,0 1,53.293 72.293L35.707,54.707A1,1 0,0 1,35.707 53.293L53.293,35.707A1,1 0,0 1,54.707 35.707z"
+ android:fillColor="#00000000"
+ android:strokeColor="#ffffff"/>
+ <path
+ android:pathData="M55.237,35.177L72.823,52.763A1.75,1.75 67.835,0 1,72.823 55.237L55.237,72.823A1.75,1.75 77.684,0 1,52.763 72.823L35.177,55.237A1.75,1.75 0,0 1,35.177 52.763L52.763,35.177A1.75,1.75 0,0 1,55.237 35.177z"
+ android:strokeWidth="1.5"
+ android:fillColor="#00000000"
+ android:strokeColor="#ffffff"/>
+ <path
+ android:pathData="M44.5,44.5h19v19h-19z"
+ android:strokeWidth="0.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#ffffff"/>
+ <path
+ android:pathData="M54,44.5l9.5,9.5l-9.5,9.5l-9.5,-9.5z"
+ android:strokeWidth="0.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#ffffff"/>
+ <path
+ android:pathData="M54,35V73"
+ android:strokeWidth="0.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#ffffff"/>
+ <path
+ android:pathData="M73,54L35,54"
+ android:strokeWidth="0.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#ffffff"/>
+ <path
+ android:pathData="M33.576,31.135l1.146,1.146l-1.146,1.146l-1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M31.146,65.966l1.146,1.146l-1.146,1.146l-1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M26.718,56l1.718,1.718l-1.718,1.718l-1.718,-1.718z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M31.146,48l1.146,1.146l-1.146,1.146l-1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M41.925,34.374l1.718,1.718l-1.718,1.718l-1.718,-1.718z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M63.146,71l1.146,1.146l-1.146,1.146l-1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M48.567,74.553l1.718,1.718l-1.718,1.718l-1.718,-1.718z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M51.146,26l1.146,1.146l-1.146,1.146l-1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M72.291,32.146l-1.146,1.146l-1.146,-1.146l1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M76.531,36.417l-1.718,1.718l-1.718,-1.718l1.718,-1.718z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M58.291,32.146l-1.146,1.146l-1.146,-1.146l1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M68.419,36.978l-1.146,1.146l-1.146,-1.146l1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M74.252,64.034l-1.146,1.146l-1.146,-1.146l1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M71.437,76.718l-1.718,1.718l-1.718,-1.718l1.718,-1.718z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M42.984,69.38l-1.146,1.146l-1.146,-1.146l1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M82.437,51.718l-1.718,1.718l-1.718,-1.718l1.718,-1.718z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M40.65,63.013C40.722,62.922 40.716,62.789 40.633,62.707V62.707C40.537,62.61 40.377,62.62 40.292,62.727C34.567,69.881 31.569,75.536 33.089,77.056C35.366,79.333 46.923,71.469 58.901,59.491C60.049,58.343 61.159,57.199 62.226,56.066C62.342,55.943 62.339,55.751 62.219,55.632L61.566,54.978C61.441,54.854 61.238,54.857 61.117,54.985C60.057,56.11 58.951,57.25 57.806,58.395C46.882,69.319 36.496,76.646 34.61,74.759C33.417,73.567 35.903,68.982 40.65,63.013Z"
+ android:fillColor="#ffffff"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M67.956,52.033C68.205,51.966 68.462,52.115 68.529,52.364C68.596,52.614 68.448,52.871 68.198,52.938L67.956,52.033ZM68.198,52.938L63.926,54.083L63.683,53.178L67.956,52.033L68.198,52.938Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M64.497,49.237C64.564,48.987 64.821,48.839 65.071,48.906C65.32,48.972 65.469,49.229 65.402,49.479L64.497,49.237ZM65.402,49.479L64.257,53.752L63.352,53.509L64.497,49.237L65.402,49.479Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M66.145,51.236C64.869,49.961 62.83,49.931 61.591,51.17L58.825,53.937C58.585,54.176 58.585,54.564 58.825,54.803C59.063,55.042 59.452,55.042 59.691,54.803L60.436,54.057C60.915,53.579 61.69,53.579 62.169,54.057L63.324,55.212C63.802,55.691 63.802,56.466 63.324,56.945L62.578,57.69C62.339,57.929 62.339,58.318 62.578,58.556C62.817,58.796 63.205,58.796 63.444,58.556L66.211,55.79C67.45,54.551 67.42,52.512 66.145,51.236Z"
+ android:fillColor="#ffffff"/>
+</vector>
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/DreamUniverse.kt b/packages/EasterEgg/src/com/android/egg/landroid/DreamUniverse.kt
index 8c87c5d4af7b..d56e8b9e8d0e 100644
--- a/packages/EasterEgg/src/com/android/egg/landroid/DreamUniverse.kt
+++ b/packages/EasterEgg/src/com/android/egg/landroid/DreamUniverse.kt
@@ -59,7 +59,7 @@ class DreamUniverse : DreamService() {
override fun onAttachedToWindow() {
super.onAttachedToWindow()
- val universe = VisibleUniverse(namer = Namer(resources), randomSeed = randomSeed())
+ val universe = Universe(namer = Namer(resources), randomSeed = randomSeed())
isInteractive = false
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/MainActivity.kt b/packages/EasterEgg/src/com/android/egg/landroid/MainActivity.kt
index 16ec1a933d92..4f77b00b7570 100644
--- a/packages/EasterEgg/src/com/android/egg/landroid/MainActivity.kt
+++ b/packages/EasterEgg/src/com/android/egg/landroid/MainActivity.kt
@@ -26,7 +26,6 @@ import androidx.activity.enableEdgeToEdge
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.withInfiniteAnimationFrameNanos
-import androidx.compose.foundation.Canvas
import androidx.compose.foundation.border
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.forEachGesture
@@ -45,6 +44,7 @@ import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.currentRecomposeScope
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -64,7 +64,6 @@ import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.text.toUpperCase
import androidx.compose.ui.tooling.preview.Devices
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@@ -75,6 +74,9 @@ import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.window.layout.FoldingFeature
import androidx.window.layout.WindowInfoTracker
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
import java.lang.Float.max
import java.lang.Float.min
import java.util.Calendar
@@ -83,9 +85,6 @@ import kotlin.math.absoluteValue
import kotlin.math.floor
import kotlin.math.sqrt
import kotlin.random.Random
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
enum class RandomSeedType {
Fixed,
@@ -139,7 +138,6 @@ fun getDessertCode(): String =
else -> Build.VERSION.RELEASE_OR_CODENAME.replace(Regex("[a-z]*"), "")
}
-
val DEBUG_TEXT = mutableStateOf("Hello Universe")
const val SHOW_DEBUG_TEXT = false
@@ -158,7 +156,7 @@ fun DebugText(text: MutableState<String>) {
}
@Composable
-fun Telemetry(universe: VisibleUniverse) {
+fun Telemetry(universe: Universe) {
var topVisible by remember { mutableStateOf(false) }
var bottomVisible by remember { mutableStateOf(false) }
@@ -180,10 +178,15 @@ fun Telemetry(universe: VisibleUniverse) {
topVisible = true
}
- universe.triggerDraw.value // recompose on every frame
-
val explored = universe.planets.filter { it.explored }
+ // TODO: Narrow the scope of invalidation here to the specific data needed;
+ // the behavior below mimics the previous implementation of a snapshot ticker value
+ val recomposeScope = currentRecomposeScope
+ Telescope(universe) {
+ recomposeScope.invalidate()
+ }
+
BoxWithConstraints(
modifier =
Modifier.fillMaxSize().padding(6.dp).windowInsetsPadding(WindowInsets.safeContent),
@@ -299,7 +302,7 @@ class MainActivity : ComponentActivity() {
enableEdgeToEdge()
- val universe = VisibleUniverse(namer = Namer(resources), randomSeed = randomSeed())
+ val universe = Universe(namer = Namer(resources), randomSeed = randomSeed())
if (TEST_UNIVERSE) {
universe.initTest()
@@ -373,7 +376,7 @@ class MainActivity : ComponentActivity() {
@Preview(name = "tablet", device = Devices.TABLET)
@Composable
fun MainActivityPreview() {
- val universe = VisibleUniverse(namer = Namer(Resources.getSystem()), randomSeed = randomSeed())
+ val universe = Universe(namer = Namer(Resources.getSystem()), randomSeed = randomSeed())
universe.initTest()
@@ -458,12 +461,12 @@ fun FlightStick(
@Composable
fun Spaaaace(
modifier: Modifier,
- u: VisibleUniverse,
+ u: Universe,
foldState: MutableState<FoldingFeature?> = mutableStateOf(null)
) {
LaunchedEffect(u) {
while (true) withInfiniteAnimationFrameNanos { frameTimeNanos ->
- u.simulateAndDrawFrame(frameTimeNanos)
+ u.step(frameTimeNanos)
}
}
@@ -492,7 +495,7 @@ fun Spaaaace(
val centerFracY: Float by
animateFloatAsState(if (halfFolded && horizontalFold) 0.25f else 0.5f, label = "centerY")
- Canvas(modifier = canvasModifier) {
+ UniverseCanvas(u, canvasModifier) { u ->
drawRect(Colors.Eigengrau, Offset.Zero, size)
val closest = u.closestPlanet()
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/Physics.kt b/packages/EasterEgg/src/com/android/egg/landroid/Physics.kt
index d14234ec66d9..b8c68818888a 100644
--- a/packages/EasterEgg/src/com/android/egg/landroid/Physics.kt
+++ b/packages/EasterEgg/src/com/android/egg/landroid/Physics.kt
@@ -17,6 +17,8 @@
package com.android.egg.landroid
import android.util.ArraySet
+import androidx.compose.ui.util.fastForEach
+import kotlinx.coroutines.DisposableHandle
import kotlin.random.Random
// artificially speed up or slow down the simulation
@@ -127,6 +129,7 @@ open class Simulator(val randomSeed: Long) {
val rng = Random(randomSeed)
val entities = ArraySet<Entity>(1000)
val constraints = ArraySet<Constraint>(100)
+ private val simStepListeners = mutableListOf<() -> Unit>()
fun add(e: Entity) = entities.add(e)
fun remove(e: Entity) = entities.remove(e)
@@ -169,5 +172,26 @@ open class Simulator(val randomSeed: Long) {
// 3. compute new velocities from updated positions and saved positions
postUpdateAll(dt, localEntities)
+
+ // 4. notify listeners that step is complete
+ simStepListeners.fastForEach { it.invoke() }
+ }
+
+ /**
+ * Register [listener] to be invoked every time the [Simulator] completes one [step].
+ * Use this to enqueue drawing.
+ *
+ * Instead of the usual register()/unregister() pattern, we're going to borrow
+ * [kotlinx.coroutines.DisposableHandle] here. Call [DisposableHandle.dispose] on the return
+ * value to unregister.
+ */
+ fun addSimulationStepListener(listener: () -> Unit): DisposableHandle {
+ // add to listener list
+ simStepListeners += listener
+
+ return DisposableHandle {
+ // on dispose, remove from listener list
+ simStepListeners -= listener
+ }
}
}
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt b/packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt
index ed3ebc7bf9a5..c476d5cf0b8b 100644
--- a/packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt
+++ b/packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt
@@ -16,19 +16,31 @@
package com.android.egg.landroid
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.RememberObserver
+import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.PathEffect
import androidx.compose.ui.graphics.PointMode
+import androidx.compose.ui.graphics.drawscope.ContentDrawScope
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.drawscope.rotateRad
import androidx.compose.ui.graphics.drawscope.scale
import androidx.compose.ui.graphics.drawscope.translate
+import androidx.compose.ui.node.DrawModifierNode
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.node.invalidateDraw
import androidx.compose.ui.util.lerp
import androidx.core.math.MathUtils.clamp
import com.android.egg.flags.Flags.flagFlag
+import kotlinx.coroutines.DisposableHandle
import java.lang.Float.max
import kotlin.math.exp
import kotlin.math.sqrt
@@ -55,22 +67,108 @@ fun DrawScope.zoom(zoom: Float, block: ZoomedDrawScope.() -> Unit) {
ds.scale(zoom) { block(ds) }
}
-class VisibleUniverse(namer: Namer, randomSeed: Long) : Universe(namer, randomSeed) {
- // Magic variable. Every time we update it, Compose will notice and redraw the universe.
- val triggerDraw = mutableStateOf(0L)
+/**
+ * A device for observing changes to a [Simulator] such as a [Universe].
+ * [observer] will be invoked each time a [Simulator.step] has completed.
+ */
+@Composable
+fun <S : Simulator> Telescope(
+ subject: S,
+ observer: (S) -> Unit
+) {
+ remember(subject) {
+ object : RememberObserver {
+ lateinit var registration: DisposableHandle
+ var currentObserver by mutableStateOf(observer)
+
+ override fun onRemembered() {
+ registration = subject.addSimulationStepListener { currentObserver(subject) }
+ }
+
+ override fun onForgotten() {
+ registration.dispose()
+ }
+
+ override fun onAbandoned() {}
+ }
+ }.currentObserver = observer
+}
+
+fun Modifier.drawUniverse(
+ universe: Universe,
+ draw: DrawScope.(Universe) -> Unit
+): Modifier = this then UniverseElement(universe, draw)
+
+@Composable
+fun UniverseCanvas(
+ universe: Universe,
+ modifier: Modifier = Modifier,
+ draw: DrawScope.(Universe) -> Unit
+) {
+ Spacer(modifier.drawUniverse(universe, draw))
+}
+
+private class UniverseElement(
+ val universe: Universe,
+ val draw: DrawScope.(Universe) -> Unit
+) : ModifierNodeElement<UniverseModifierNode>() {
+ override fun create(): UniverseModifierNode = UniverseModifierNode(universe, draw)
+
+ // Called when a modifier is applied to a Layout whose inputs have changed
+ override fun update(node: UniverseModifierNode) {
+ node.universe = universe
+ node.draw = draw
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
- fun simulateAndDrawFrame(nanos: Long) {
- // By writing this value, Compose will look for functions that read it (like drawZoomed).
- triggerDraw.value = nanos
+ other as UniverseElement
- step(nanos)
+ if (universe != other.universe) return false
+ if (draw != other.draw) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = universe.hashCode()
+ result = 31 * result + draw.hashCode()
+ return result
}
}
-fun ZoomedDrawScope.drawUniverse(universe: VisibleUniverse) {
- with(universe) {
- triggerDraw.value // Please recompose when this value changes.
+private class UniverseModifierNode(
+ universe: Universe,
+ draw: DrawScope.(Universe) -> Unit,
+) : Modifier.Node(), DrawModifierNode {
+ private val universeListener: () -> Unit = { invalidateDraw() }
+ private var removeUniverseListener: DisposableHandle? =
+ universe.addSimulationStepListener(universeListener)
+
+ var universe: Universe = universe
+ set(value) {
+ if (field === value) return
+ removeUniverseListener?.dispose()
+ field = value
+ removeUniverseListener = value.addSimulationStepListener(universeListener)
+ }
+
+ var draw: ContentDrawScope.(Universe) -> Unit = draw
+ set(value) {
+ if (field === value) return
+ field = value
+ invalidateDraw()
+ }
+ override fun ContentDrawScope.draw() {
+ draw(universe)
+ }
+}
+
+fun ZoomedDrawScope.drawUniverse(universe: Universe) {
+ with(universe) {
constraints.forEach {
when (it) {
is Landing -> drawLanding(it)
diff --git a/packages/InputDevices/res/values-af/strings.xml b/packages/InputDevices/res/values-af/strings.xml
index cd9d915d87fd..e364576c4001 100644
--- a/packages/InputDevices/res/values-af/strings.xml
+++ b/packages/InputDevices/res/values-af/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegryns (Latyns)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serwies (Cyrillies)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegryns (Cyrillies)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Roemeens"</string>
</resources>
diff --git a/packages/InputDevices/res/values-am/strings.xml b/packages/InputDevices/res/values-am/strings.xml
index a6f5f3a7018f..db5a7d404a58 100644
--- a/packages/InputDevices/res/values-am/strings.xml
+++ b/packages/InputDevices/res/values-am/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"ሞንቴኔግሮኛ (ላቲን)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"ሰርቢያኛ (ሲሪሊክኛ)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"ሞንቴኔግሮኛ (ሲሪሊክኛ)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"ሮማኒያኛ"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ar/strings.xml b/packages/InputDevices/res/values-ar/strings.xml
index f92d0def3b7e..65f3edb2604c 100644
--- a/packages/InputDevices/res/values-ar/strings.xml
+++ b/packages/InputDevices/res/values-ar/strings.xml
@@ -56,4 +56,6 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"لغة الجبل الأسود (اللاتينية)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"الصربية (السيريلية)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"لغة الجبل الأسود (السيريلية)"</string>
+ <!-- no translation found for keyboard_layout_romanian (8698989892731726903) -->
+ <skip />
</resources>
diff --git a/packages/InputDevices/res/values-as/strings.xml b/packages/InputDevices/res/values-as/strings.xml
index 8084da395175..c4eaafb195c9 100644
--- a/packages/InputDevices/res/values-as/strings.xml
+++ b/packages/InputDevices/res/values-as/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"মণ্টেনেগ্ৰিণ (লেটিন)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"ছাৰ্বিয়ান (চিৰিলিক)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"মণ্টেনেগ্ৰিণ (চিৰিলিক)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"ৰোমানিয়ান"</string>
</resources>
diff --git a/packages/InputDevices/res/values-az/strings.xml b/packages/InputDevices/res/values-az/strings.xml
index 068a771d9c50..d71c3960601d 100644
--- a/packages/InputDevices/res/values-az/strings.xml
+++ b/packages/InputDevices/res/values-az/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Monteneqro dili (Latın)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serb dili (Kiril)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Monteneqro dili (Kiril)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumın dili"</string>
</resources>
diff --git a/packages/InputDevices/res/values-b+sr+Latn/strings.xml b/packages/InputDevices/res/values-b+sr+Latn/strings.xml
index 334b03218f91..e670ed4f843c 100644
--- a/packages/InputDevices/res/values-b+sr+Latn/strings.xml
+++ b/packages/InputDevices/res/values-b+sr+Latn/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"crnogorski (latinica)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"srpski (ćirilica)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"crnogorski (ćirilica)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"rumunski"</string>
</resources>
diff --git a/packages/InputDevices/res/values-be/strings.xml b/packages/InputDevices/res/values-be/strings.xml
index c11266512978..c8c04d400eb8 100644
--- a/packages/InputDevices/res/values-be/strings.xml
+++ b/packages/InputDevices/res/values-be/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Чарнагорская (лацініца)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Сербская (кірыліца)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Чарнагорская (кірыліца)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Румынская"</string>
</resources>
diff --git a/packages/InputDevices/res/values-bg/strings.xml b/packages/InputDevices/res/values-bg/strings.xml
index 8a650b283f4f..82c39657b003 100644
--- a/packages/InputDevices/res/values-bg/strings.xml
+++ b/packages/InputDevices/res/values-bg/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"черногорски (латиница)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"сръбски (кирилица)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"черногорски (кирилица)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"румънски"</string>
</resources>
diff --git a/packages/InputDevices/res/values-bn/strings.xml b/packages/InputDevices/res/values-bn/strings.xml
index 02ab5075b991..de54cdf688c4 100644
--- a/packages/InputDevices/res/values-bn/strings.xml
+++ b/packages/InputDevices/res/values-bn/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"মন্টেনেগ্রিন (ল্যাটিন)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"সার্বিয়ান (সিরিলিক)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"মন্টেনেগ্রিন (সিরিলিক)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"রোমানিয়ান"</string>
</resources>
diff --git a/packages/InputDevices/res/values-bs/strings.xml b/packages/InputDevices/res/values-bs/strings.xml
index e1aef5d67d89..9b7b33112643 100644
--- a/packages/InputDevices/res/values-bs/strings.xml
+++ b/packages/InputDevices/res/values-bs/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"crnogorski (latinica)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"srpski (ćirilica)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"crnogorski (ćirilica)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"rumunski"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ca/strings.xml b/packages/InputDevices/res/values-ca/strings.xml
index f9b2e5eb342a..874e06bb69cf 100644
--- a/packages/InputDevices/res/values-ca/strings.xml
+++ b/packages/InputDevices/res/values-ca/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrí (llatí)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbi (ciríl·lic)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrí (ciríl·lic)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romanès"</string>
</resources>
diff --git a/packages/InputDevices/res/values-cs/strings.xml b/packages/InputDevices/res/values-cs/strings.xml
index 72efbc4cc999..6a46b1473089 100644
--- a/packages/InputDevices/res/values-cs/strings.xml
+++ b/packages/InputDevices/res/values-cs/strings.xml
@@ -56,4 +56,6 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"černohorština (latinka)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"srbština (cyrilice)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"černohorština (cyrilice)"</string>
+ <!-- no translation found for keyboard_layout_romanian (8698989892731726903) -->
+ <skip />
</resources>
diff --git a/packages/InputDevices/res/values-da/strings.xml b/packages/InputDevices/res/values-da/strings.xml
index 6ce0b8b9febe..246baba5be18 100644
--- a/packages/InputDevices/res/values-da/strings.xml
+++ b/packages/InputDevices/res/values-da/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrinsk (latinsk)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbisk (kyrillisk)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrinsk (kyrillisk)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumænsk"</string>
</resources>
diff --git a/packages/InputDevices/res/values-de/strings.xml b/packages/InputDevices/res/values-de/strings.xml
index 0dc4e2a0aa49..21a939a3d007 100644
--- a/packages/InputDevices/res/values-de/strings.xml
+++ b/packages/InputDevices/res/values-de/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrinisch (lat. Alphabet)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbisch (kyrillisch)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrinisch (kyrillisch)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumänisch"</string>
</resources>
diff --git a/packages/InputDevices/res/values-el/strings.xml b/packages/InputDevices/res/values-el/strings.xml
index 08357db6b06b..eabb90c86daf 100644
--- a/packages/InputDevices/res/values-el/strings.xml
+++ b/packages/InputDevices/res/values-el/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Μαυροβουνιακά (Λατινικά)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Σερβικά (Κυριλλικά)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Μαυροβουνιακά (Κυριλλικά)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Ρουμανικά"</string>
</resources>
diff --git a/packages/InputDevices/res/values-en-rAU/strings.xml b/packages/InputDevices/res/values-en-rAU/strings.xml
index 0e9e6ebb7f38..7b72cba5c863 100644
--- a/packages/InputDevices/res/values-en-rAU/strings.xml
+++ b/packages/InputDevices/res/values-en-rAU/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrin (Latin)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbian (Cyrillic)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrin (Cyrillic)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romanian"</string>
</resources>
diff --git a/packages/InputDevices/res/values-en-rCA/strings.xml b/packages/InputDevices/res/values-en-rCA/strings.xml
index 3fa4bce3dfc3..d78dce2ff927 100644
--- a/packages/InputDevices/res/values-en-rCA/strings.xml
+++ b/packages/InputDevices/res/values-en-rCA/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrin (Latin)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbian (Cyrillic)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrin (Cyrillic)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romanian"</string>
</resources>
diff --git a/packages/InputDevices/res/values-en-rGB/strings.xml b/packages/InputDevices/res/values-en-rGB/strings.xml
index 0e9e6ebb7f38..7b72cba5c863 100644
--- a/packages/InputDevices/res/values-en-rGB/strings.xml
+++ b/packages/InputDevices/res/values-en-rGB/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrin (Latin)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbian (Cyrillic)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrin (Cyrillic)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romanian"</string>
</resources>
diff --git a/packages/InputDevices/res/values-en-rIN/strings.xml b/packages/InputDevices/res/values-en-rIN/strings.xml
index 0e9e6ebb7f38..7b72cba5c863 100644
--- a/packages/InputDevices/res/values-en-rIN/strings.xml
+++ b/packages/InputDevices/res/values-en-rIN/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrin (Latin)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbian (Cyrillic)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrin (Cyrillic)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romanian"</string>
</resources>
diff --git a/packages/InputDevices/res/values-es-rUS/strings.xml b/packages/InputDevices/res/values-es-rUS/strings.xml
index 321b9a595dfa..2a4035ad5eed 100644
--- a/packages/InputDevices/res/values-es-rUS/strings.xml
+++ b/packages/InputDevices/res/values-es-rUS/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrino (latino)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbio (cirílico)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrino (cirílico)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumano"</string>
</resources>
diff --git a/packages/InputDevices/res/values-es/strings.xml b/packages/InputDevices/res/values-es/strings.xml
index 98076524b5e8..ba1ef20e24b6 100644
--- a/packages/InputDevices/res/values-es/strings.xml
+++ b/packages/InputDevices/res/values-es/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrino (latino)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbio (cirílico)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrino (cirílico)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumano"</string>
</resources>
diff --git a/packages/InputDevices/res/values-et/strings.xml b/packages/InputDevices/res/values-et/strings.xml
index eb7ea9fd2843..99f36260cc41 100644
--- a/packages/InputDevices/res/values-et/strings.xml
+++ b/packages/InputDevices/res/values-et/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegro (ladina)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"serbia (kirillitsa)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"montenegro (kirillitsa)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"rumeenia"</string>
</resources>
diff --git a/packages/InputDevices/res/values-eu/strings.xml b/packages/InputDevices/res/values-eu/strings.xml
index 53707598b264..9fae4f99b09d 100644
--- a/packages/InputDevices/res/values-eu/strings.xml
+++ b/packages/InputDevices/res/values-eu/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegroarra (latindarra)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbiarra (zirilikoa)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegroarra (zirilikoa)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Errumaniera"</string>
</resources>
diff --git a/packages/InputDevices/res/values-fa/strings.xml b/packages/InputDevices/res/values-fa/strings.xml
index 9bbf4e36fa16..cbc6b65148b9 100644
--- a/packages/InputDevices/res/values-fa/strings.xml
+++ b/packages/InputDevices/res/values-fa/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"مونته‌نگرویی (لاتین)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"صربی (سیریلیک)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"مونته‌نگرویی (سیریلیک)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"رومانیایی"</string>
</resources>
diff --git a/packages/InputDevices/res/values-fi/strings.xml b/packages/InputDevices/res/values-fi/strings.xml
index 3e88c2085373..736d7cbd77c3 100644
--- a/packages/InputDevices/res/values-fi/strings.xml
+++ b/packages/InputDevices/res/values-fi/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"montenegro (latinalainen)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"serbia (kyrillinen)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"montenegro (kyrillinen)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"romania"</string>
</resources>
diff --git a/packages/InputDevices/res/values-fr-rCA/strings.xml b/packages/InputDevices/res/values-fr-rCA/strings.xml
index 690fbad6ab12..7b99d3bc33bc 100644
--- a/packages/InputDevices/res/values-fr-rCA/strings.xml
+++ b/packages/InputDevices/res/values-fr-rCA/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Monténégrin (latin)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbe (cyrillique)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Monténégrin (cyrillique)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Roumain"</string>
</resources>
diff --git a/packages/InputDevices/res/values-fr/strings.xml b/packages/InputDevices/res/values-fr/strings.xml
index 70bd250738f7..8628f8f7c0eb 100644
--- a/packages/InputDevices/res/values-fr/strings.xml
+++ b/packages/InputDevices/res/values-fr/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Monténégrin (latin)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbe (cyrillique)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Monténégrin (cyrillique)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Roumain"</string>
</resources>
diff --git a/packages/InputDevices/res/values-gl/strings.xml b/packages/InputDevices/res/values-gl/strings.xml
index 058dba52e17b..5e681e6032dc 100644
--- a/packages/InputDevices/res/values-gl/strings.xml
+++ b/packages/InputDevices/res/values-gl/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrino (alfabeto latino)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbio (cirílico)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrino (cirílico)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romanés"</string>
</resources>
diff --git a/packages/InputDevices/res/values-gu/strings.xml b/packages/InputDevices/res/values-gu/strings.xml
index 3f1b31a8a6c8..a5a522ecbf31 100644
--- a/packages/InputDevices/res/values-gu/strings.xml
+++ b/packages/InputDevices/res/values-gu/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"મોંટેનેગ્રીન (લેટિન)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"સર્બિયન (સિરિલિક)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"મોંટેનેગ્રીન (સિરિલિક)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"રોમાનિયન"</string>
</resources>
diff --git a/packages/InputDevices/res/values-hi/strings.xml b/packages/InputDevices/res/values-hi/strings.xml
index db59ebac7805..ad9c980d00a9 100644
--- a/packages/InputDevices/res/values-hi/strings.xml
+++ b/packages/InputDevices/res/values-hi/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"मॉन्टेनीग्रिन (लैटिन)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"सर्बियन (सिरिलिक)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"मोंटेनेग्रिन (सिरिलिक)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"रोमेनियन"</string>
</resources>
diff --git a/packages/InputDevices/res/values-hr/strings.xml b/packages/InputDevices/res/values-hr/strings.xml
index 905dce25b4aa..b7e8ee4cad17 100644
--- a/packages/InputDevices/res/values-hr/strings.xml
+++ b/packages/InputDevices/res/values-hr/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"crnogorski (latinica)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"srpski (ćirilica)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"crnogorski (ćirilica)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"rumunjski"</string>
</resources>
diff --git a/packages/InputDevices/res/values-hu/strings.xml b/packages/InputDevices/res/values-hu/strings.xml
index 4c8e7b8de6ba..756cc0846ff2 100644
--- a/packages/InputDevices/res/values-hu/strings.xml
+++ b/packages/InputDevices/res/values-hu/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"montenegrói (latin betűs)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"szerb (cirill betűs)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"montenegrói (cirill betűs)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"román"</string>
</resources>
diff --git a/packages/InputDevices/res/values-hy/strings.xml b/packages/InputDevices/res/values-hy/strings.xml
index ae56fc5b1620..eced5cdbde2d 100644
--- a/packages/InputDevices/res/values-hy/strings.xml
+++ b/packages/InputDevices/res/values-hy/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"չեռնոգորերեն (լատինատառ)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"սերբերեն (կյուրեղատառ)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"չեռնոգորերեն (կյուրեղատառ)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Ռումիներեն"</string>
</resources>
diff --git a/packages/InputDevices/res/values-in/strings.xml b/packages/InputDevices/res/values-in/strings.xml
index 52bc03943abd..e871d1947fab 100644
--- a/packages/InputDevices/res/values-in/strings.xml
+++ b/packages/InputDevices/res/values-in/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegro (Latin)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbia (Sirilik)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegro (Sirilik)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumania"</string>
</resources>
diff --git a/packages/InputDevices/res/values-is/strings.xml b/packages/InputDevices/res/values-is/strings.xml
index 0f516cef370e..ec5d98b24ec6 100644
--- a/packages/InputDevices/res/values-is/strings.xml
+++ b/packages/InputDevices/res/values-is/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Svartfellska (latneskt)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbneska (kyrillískt)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Svartfellska (kyrillískt)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"rúmenska"</string>
</resources>
diff --git a/packages/InputDevices/res/values-it/strings.xml b/packages/InputDevices/res/values-it/strings.xml
index f77b87cc67be..06ceb7affeeb 100644
--- a/packages/InputDevices/res/values-it/strings.xml
+++ b/packages/InputDevices/res/values-it/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrino (latino)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbo (cirillico)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrino (cirillico)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumeno"</string>
</resources>
diff --git a/packages/InputDevices/res/values-iw/strings.xml b/packages/InputDevices/res/values-iw/strings.xml
index 0e400e2d0fa4..4cf8098fded7 100644
--- a/packages/InputDevices/res/values-iw/strings.xml
+++ b/packages/InputDevices/res/values-iw/strings.xml
@@ -56,4 +56,6 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"מונטנגרית (לטינית)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"סרבית (אותיות קיריליות)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"מונטנגרית (אותיות קיריליות)"</string>
+ <!-- no translation found for keyboard_layout_romanian (8698989892731726903) -->
+ <skip />
</resources>
diff --git a/packages/InputDevices/res/values-ja/strings.xml b/packages/InputDevices/res/values-ja/strings.xml
index b1830ebda199..4c6de705565e 100644
--- a/packages/InputDevices/res/values-ja/strings.xml
+++ b/packages/InputDevices/res/values-ja/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"モンテネグロ語(ラテン)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"セルビア語(キリル)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"モンテネグロ語(キリル)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"ルーマニア語"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ka/strings.xml b/packages/InputDevices/res/values-ka/strings.xml
index 75c72b91df94..7232c1a7db9c 100644
--- a/packages/InputDevices/res/values-ka/strings.xml
+++ b/packages/InputDevices/res/values-ka/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"მონტენეგრული (ლათინური)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"სერბული (კირილიცა)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"მონტენეგრული (კირილიცა)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"რუმინული"</string>
</resources>
diff --git a/packages/InputDevices/res/values-kk/strings.xml b/packages/InputDevices/res/values-kk/strings.xml
index c0a58685bc52..278c868d76d4 100644
--- a/packages/InputDevices/res/values-kk/strings.xml
+++ b/packages/InputDevices/res/values-kk/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Черногор (латын жазуы)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Сербия (кириллица)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Черногория (кириллица)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Румын"</string>
</resources>
diff --git a/packages/InputDevices/res/values-km/strings.xml b/packages/InputDevices/res/values-km/strings.xml
index 6c3db64fa1e9..2eaeaa7f03ac 100644
--- a/packages/InputDevices/res/values-km/strings.xml
+++ b/packages/InputDevices/res/values-km/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"ម៉ុងតេណេហ្គ្រោ (ឡាតាំង)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"សែប៊ី (ស៊ីរីលីក)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"ម៉ុងតេណេហ្គ្រោ (ស៊ីរីលីក)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"រ៉ូម៉ានី"</string>
</resources>
diff --git a/packages/InputDevices/res/values-kn/strings.xml b/packages/InputDevices/res/values-kn/strings.xml
index 0f4c5229c4d4..8039039ca0fc 100644
--- a/packages/InputDevices/res/values-kn/strings.xml
+++ b/packages/InputDevices/res/values-kn/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"ಮೊಂಟೆನೆಗ್ರಿನ್ (ಲ್ಯಾಟಿನ್)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"ಸೆರ್ಬಿಯನ್ (ಸಿರಿಲಿಕ್)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"ಮೊಂಟೆನೆಗ್ರಿನ್ (ಸಿರಿಲಿಕ್)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"ರೊಮೇನಿಯನ್"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ko/strings.xml b/packages/InputDevices/res/values-ko/strings.xml
index dcfb3b4ece40..de1bb3d5dbe6 100644
--- a/packages/InputDevices/res/values-ko/strings.xml
+++ b/packages/InputDevices/res/values-ko/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"몬테네그로어(로마자)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"세르비아어(키릴 자모)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"몬테네그로어(키릴)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"루마니아어"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ky/strings.xml b/packages/InputDevices/res/values-ky/strings.xml
index c0b3d3a1d9b3..47bf7b73405f 100644
--- a/packages/InputDevices/res/values-ky/strings.xml
+++ b/packages/InputDevices/res/values-ky/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Монтенегрочо (Латын)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Сербче (Кирилл)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Черногориялыкча (Кирилл)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Румынча"</string>
</resources>
diff --git a/packages/InputDevices/res/values-lo/strings.xml b/packages/InputDevices/res/values-lo/strings.xml
index c2e5a2beded5..6a35f23b4f9e 100644
--- a/packages/InputDevices/res/values-lo/strings.xml
+++ b/packages/InputDevices/res/values-lo/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"ມອນເທເນກຣິນ (ລາຕິນ)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"ເຊີບຽນ (ຊີຣິວລິກ)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"ມອນເທເນກຣິນ (ຊີຣິວລິກ)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"ໂຣມານຽນ"</string>
</resources>
diff --git a/packages/InputDevices/res/values-lt/strings.xml b/packages/InputDevices/res/values-lt/strings.xml
index 9a98e8eb5b13..4bf9223099d1 100644
--- a/packages/InputDevices/res/values-lt/strings.xml
+++ b/packages/InputDevices/res/values-lt/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Juodkalniečių (lotynų rašmenys)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbų (kirilica)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Juodkalniečių (kirilica)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumunų"</string>
</resources>
diff --git a/packages/InputDevices/res/values-lv/strings.xml b/packages/InputDevices/res/values-lv/strings.xml
index d3422b210757..90d690ca10b7 100644
--- a/packages/InputDevices/res/values-lv/strings.xml
+++ b/packages/InputDevices/res/values-lv/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Melnkalniešu (latīņu)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbu (kirilica)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Melnkalniešu (kirilica)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumāņu"</string>
</resources>
diff --git a/packages/InputDevices/res/values-mk/strings.xml b/packages/InputDevices/res/values-mk/strings.xml
index ccb09392aed3..4c80a80af8a3 100644
--- a/packages/InputDevices/res/values-mk/strings.xml
+++ b/packages/InputDevices/res/values-mk/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"црногорски (латиница)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"српски (кирилица)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"црногорски (кирилица)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"романски"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ml/strings.xml b/packages/InputDevices/res/values-ml/strings.xml
index 5a7b601baa97..41ea10f22aa3 100644
--- a/packages/InputDevices/res/values-ml/strings.xml
+++ b/packages/InputDevices/res/values-ml/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"മോണ്ടിനെഗ്രിൻ (ലാറ്റിൻ)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"സെർബിയൻ (സിറിലിക്)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"മോണ്ടിനെഗ്രിൻ (സിറിലിക്)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"റൊമേനിയൻ"</string>
</resources>
diff --git a/packages/InputDevices/res/values-mn/strings.xml b/packages/InputDevices/res/values-mn/strings.xml
index 0044eb24bc6a..056e728f4687 100644
--- a/packages/InputDevices/res/values-mn/strings.xml
+++ b/packages/InputDevices/res/values-mn/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Монтенегро (латин)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Серби (кирилл)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Монтенегро (кирилл)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Румын"</string>
</resources>
diff --git a/packages/InputDevices/res/values-mr/strings.xml b/packages/InputDevices/res/values-mr/strings.xml
index d306dda71553..fe032fe3999e 100644
--- a/packages/InputDevices/res/values-mr/strings.xml
+++ b/packages/InputDevices/res/values-mr/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"मॉन्टेनेग्रिन (लॅटिन)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"सर्बियन (सिरिलिक)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"मॉन्टेनेग्रिन (सिरिलिक)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"रोमानियन"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ms/strings.xml b/packages/InputDevices/res/values-ms/strings.xml
index d1b16547f8e6..f9d18a1055ef 100644
--- a/packages/InputDevices/res/values-ms/strings.xml
+++ b/packages/InputDevices/res/values-ms/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrin (Latin)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbia (Cyril)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrin (Cyril)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Bahasa Romania"</string>
</resources>
diff --git a/packages/InputDevices/res/values-my/strings.xml b/packages/InputDevices/res/values-my/strings.xml
index fb553446dbd4..47498e079981 100644
--- a/packages/InputDevices/res/values-my/strings.xml
+++ b/packages/InputDevices/res/values-my/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"မွန်တီနီဂရင်း (လက်တင်)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"ဆားဘီးယား (စီရီလစ်)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"မွန်တီနီဂရင်း (စီရီလစ်)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"ရိုမေးနီးယား"</string>
</resources>
diff --git a/packages/InputDevices/res/values-nb/strings.xml b/packages/InputDevices/res/values-nb/strings.xml
index 7ac2a822667a..954462c783ff 100644
--- a/packages/InputDevices/res/values-nb/strings.xml
+++ b/packages/InputDevices/res/values-nb/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrisk (latinsk)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbisk (kyrillisk)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrisk (kyrillisk)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumensk"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ne/strings.xml b/packages/InputDevices/res/values-ne/strings.xml
index 113489d65d96..e2804d4a89b5 100644
--- a/packages/InputDevices/res/values-ne/strings.xml
+++ b/packages/InputDevices/res/values-ne/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"मोन्टेनिग्रिन (ल्याटिन)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"सर्बियाली (सिरिलिक)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"मोन्टेनिग्रिन (सिरिलिक)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"रोमानियाली"</string>
</resources>
diff --git a/packages/InputDevices/res/values-nl/strings.xml b/packages/InputDevices/res/values-nl/strings.xml
index 0e954e9b9ed3..67f78bad4158 100644
--- a/packages/InputDevices/res/values-nl/strings.xml
+++ b/packages/InputDevices/res/values-nl/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrijns (Latijns)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Servisch (Cyrillisch)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrijns (Cyrillisch)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Roemeens"</string>
</resources>
diff --git a/packages/InputDevices/res/values-or/strings.xml b/packages/InputDevices/res/values-or/strings.xml
index d9d852008275..c6e020cae6d0 100644
--- a/packages/InputDevices/res/values-or/strings.xml
+++ b/packages/InputDevices/res/values-or/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"ମଣ୍ଟେନେଗ୍ରିନ (ଲାଟିନ)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"ସର୍ବିଆନ (ସିରିଲିକ)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"ମଣ୍ଟେନେଗ୍ରିନ (ସିରିଲିକ)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"ରୋମାନିଆନ"</string>
</resources>
diff --git a/packages/InputDevices/res/values-pa/strings.xml b/packages/InputDevices/res/values-pa/strings.xml
index 85b0d195f05f..29c3b7d14bb2 100644
--- a/packages/InputDevices/res/values-pa/strings.xml
+++ b/packages/InputDevices/res/values-pa/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"ਮਾਂਟੇਨੀਗਰਿਨ (ਲਾਤੀਨੀ)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"ਸਰਬੀਆਈ (ਸਿਰਿਲਿਕ)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"ਮਾਂਟੇਨੀਗਰਿਨ (ਸਿਰਿਲਿਕ)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"ਰੋਮਾਨੀਆਈ"</string>
</resources>
diff --git a/packages/InputDevices/res/values-pl/strings.xml b/packages/InputDevices/res/values-pl/strings.xml
index 7fb90d2454f6..8ce00d3947b8 100644
--- a/packages/InputDevices/res/values-pl/strings.xml
+++ b/packages/InputDevices/res/values-pl/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"czarnogórski (alfabet łaciński)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"serbski (cyrylica)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"czarnogórski (cyrylica)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"rumuński"</string>
</resources>
diff --git a/packages/InputDevices/res/values-pt-rBR/strings.xml b/packages/InputDevices/res/values-pt-rBR/strings.xml
index 2b92c811be64..3b1fc9b888d9 100644
--- a/packages/InputDevices/res/values-pt-rBR/strings.xml
+++ b/packages/InputDevices/res/values-pt-rBR/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrino (latim)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Sérvio (cirílico)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrino (cirílico)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romeno"</string>
</resources>
diff --git a/packages/InputDevices/res/values-pt-rPT/strings.xml b/packages/InputDevices/res/values-pt-rPT/strings.xml
index 98cf7e2df754..163108d94367 100644
--- a/packages/InputDevices/res/values-pt-rPT/strings.xml
+++ b/packages/InputDevices/res/values-pt-rPT/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrino (latim)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Sérvio (cirílico)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrino (cirílico)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romeno"</string>
</resources>
diff --git a/packages/InputDevices/res/values-pt/strings.xml b/packages/InputDevices/res/values-pt/strings.xml
index 2b92c811be64..3b1fc9b888d9 100644
--- a/packages/InputDevices/res/values-pt/strings.xml
+++ b/packages/InputDevices/res/values-pt/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrino (latim)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Sérvio (cirílico)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrino (cirílico)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romeno"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ro/strings.xml b/packages/InputDevices/res/values-ro/strings.xml
index 71d19958263e..78c99ce4e20e 100644
--- a/packages/InputDevices/res/values-ro/strings.xml
+++ b/packages/InputDevices/res/values-ro/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Muntenegreană (caractere latine)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Sârbă (caractere chirilice)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Muntenegreană (Chirilică)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Română"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ru/strings.xml b/packages/InputDevices/res/values-ru/strings.xml
index 13130fc9ca1f..183b00e203b4 100644
--- a/packages/InputDevices/res/values-ru/strings.xml
+++ b/packages/InputDevices/res/values-ru/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Черногорский (латиница)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Сербский (кириллица)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Черногорский (кириллица)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Румынский"</string>
</resources>
diff --git a/packages/InputDevices/res/values-si/strings.xml b/packages/InputDevices/res/values-si/strings.xml
index 80c674d00bca..373dfda87874 100644
--- a/packages/InputDevices/res/values-si/strings.xml
+++ b/packages/InputDevices/res/values-si/strings.xml
@@ -56,4 +56,6 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"මොන්ටෙනේග්‍රීන් (ලතින්)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"සර්බියානු (සිරිලික්)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"මොන්ටෙනේග්‍රීන් (සිරිලික්)"</string>
+ <!-- no translation found for keyboard_layout_romanian (8698989892731726903) -->
+ <skip />
</resources>
diff --git a/packages/InputDevices/res/values-sk/strings.xml b/packages/InputDevices/res/values-sk/strings.xml
index 6ce98cc34bca..c269085202b6 100644
--- a/packages/InputDevices/res/values-sk/strings.xml
+++ b/packages/InputDevices/res/values-sk/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"čiernohorčina (latinka)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"srbčina (cyrilika)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"čiernohorčina (cyrilika)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"rumunčina"</string>
</resources>
diff --git a/packages/InputDevices/res/values-sl/strings.xml b/packages/InputDevices/res/values-sl/strings.xml
index 29264231e6f6..d2e9fd182d21 100644
--- a/packages/InputDevices/res/values-sl/strings.xml
+++ b/packages/InputDevices/res/values-sl/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"črnogorščina (latinica)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"srbščina (cirilica)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"črnogorščina (cirilica)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"romunščina"</string>
</resources>
diff --git a/packages/InputDevices/res/values-sq/strings.xml b/packages/InputDevices/res/values-sq/strings.xml
index 06f76f3d6c4a..36882cbf7986 100644
--- a/packages/InputDevices/res/values-sq/strings.xml
+++ b/packages/InputDevices/res/values-sq/strings.xml
@@ -56,4 +56,6 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Malazisht (latine)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbisht (cirilike)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Malazisht (cirilike)"</string>
+ <!-- no translation found for keyboard_layout_romanian (8698989892731726903) -->
+ <skip />
</resources>
diff --git a/packages/InputDevices/res/values-sr/strings.xml b/packages/InputDevices/res/values-sr/strings.xml
index 1172fef2c0a9..e4fed039668f 100644
--- a/packages/InputDevices/res/values-sr/strings.xml
+++ b/packages/InputDevices/res/values-sr/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"црногорски (латиница)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"српски (ћирилица)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"црногорски (ћирилица)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"румунски"</string>
</resources>
diff --git a/packages/InputDevices/res/values-sv/strings.xml b/packages/InputDevices/res/values-sv/strings.xml
index 946854ca00bb..4eaf856adde9 100644
--- a/packages/InputDevices/res/values-sv/strings.xml
+++ b/packages/InputDevices/res/values-sv/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"montenegrinska (latinskt)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"serbiska (kyrilliskt)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"montenegrinska (kyrilliskt)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"rumänska"</string>
</resources>
diff --git a/packages/InputDevices/res/values-sw/strings.xml b/packages/InputDevices/res/values-sw/strings.xml
index c3578d8b5fbd..30b52b25468c 100644
--- a/packages/InputDevices/res/values-sw/strings.xml
+++ b/packages/InputDevices/res/values-sw/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Kimontenegri (Kilatini)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Kiserbia (Kisiriliki)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Kimontenegri (Kisiriliki)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Kiromania"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ta/strings.xml b/packages/InputDevices/res/values-ta/strings.xml
index 5c3f57e361b7..d60084cd62f7 100644
--- a/packages/InputDevices/res/values-ta/strings.xml
+++ b/packages/InputDevices/res/values-ta/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"மாண்டினெக்ரன் (லத்தீன்)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"செர்பியன் (சிரிலிக்)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"மாண்டினெக்ரன் (சிரிலிக்)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"ரோமானியன்"</string>
</resources>
diff --git a/packages/InputDevices/res/values-te/strings.xml b/packages/InputDevices/res/values-te/strings.xml
index a0674d665ed9..2f40442de757 100644
--- a/packages/InputDevices/res/values-te/strings.xml
+++ b/packages/InputDevices/res/values-te/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"మాంటెనెగ్రిన్ (లాటిన్)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"సెర్బియన్ (సిరిలిక్)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"మాంటెనెగ్రిన్ (సిరిలిక్)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"రొమేనియన్"</string>
</resources>
diff --git a/packages/InputDevices/res/values-th/strings.xml b/packages/InputDevices/res/values-th/strings.xml
index a9465961f06a..ae10f0409760 100644
--- a/packages/InputDevices/res/values-th/strings.xml
+++ b/packages/InputDevices/res/values-th/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"มอนเตเนโกร (ละติน)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"เซอร์เบีย (ซีริลลิก)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"มอนเตเนโกร (ซีริลลิก)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"โรมาเนีย"</string>
</resources>
diff --git a/packages/InputDevices/res/values-tl/strings.xml b/packages/InputDevices/res/values-tl/strings.xml
index 0a5d3cc6c1d6..dc0d1f52fe8f 100644
--- a/packages/InputDevices/res/values-tl/strings.xml
+++ b/packages/InputDevices/res/values-tl/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrin (Latin)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbian (Cyrillic)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrin (Cyrillic)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romanian"</string>
</resources>
diff --git a/packages/InputDevices/res/values-tr/strings.xml b/packages/InputDevices/res/values-tr/strings.xml
index f37a098f0714..2e7084d43cdd 100644
--- a/packages/InputDevices/res/values-tr/strings.xml
+++ b/packages/InputDevices/res/values-tr/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Karadağca (Latin)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Sırpça (Kiril)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Karadağca (Kiril)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumence"</string>
</resources>
diff --git a/packages/InputDevices/res/values-uk/strings.xml b/packages/InputDevices/res/values-uk/strings.xml
index d496dfa3910b..1010177539b1 100644
--- a/packages/InputDevices/res/values-uk/strings.xml
+++ b/packages/InputDevices/res/values-uk/strings.xml
@@ -56,4 +56,6 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Чорногорська (латиниця)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Сербська (кирилиця)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Чорногорська (кирилиця)"</string>
+ <!-- no translation found for keyboard_layout_romanian (8698989892731726903) -->
+ <skip />
</resources>
diff --git a/packages/InputDevices/res/values-ur/strings.xml b/packages/InputDevices/res/values-ur/strings.xml
index 7293858ee413..94cd329ff442 100644
--- a/packages/InputDevices/res/values-ur/strings.xml
+++ b/packages/InputDevices/res/values-ur/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"مونٹے نیگریائی (لاطینی)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"سربیائی (سیریلک)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"مونٹے نیگریائی (سیریلک)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"رومانیائی"</string>
</resources>
diff --git a/packages/InputDevices/res/values-uz/strings.xml b/packages/InputDevices/res/values-uz/strings.xml
index f212e2c4108e..92e00d81c622 100644
--- a/packages/InputDevices/res/values-uz/strings.xml
+++ b/packages/InputDevices/res/values-uz/strings.xml
@@ -56,4 +56,6 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Chernogor (lotin)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serb (kirill)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Chernogor (kirill)"</string>
+ <!-- no translation found for keyboard_layout_romanian (8698989892731726903) -->
+ <skip />
</resources>
diff --git a/packages/InputDevices/res/values-vi/strings.xml b/packages/InputDevices/res/values-vi/strings.xml
index f3d2cc48fb96..8384c3ec0652 100644
--- a/packages/InputDevices/res/values-vi/strings.xml
+++ b/packages/InputDevices/res/values-vi/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Tiếng Montenegro (Latinh)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Tiếng Serbia (Chữ Kirin)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Tiếng Montenegro (Chữ Kirin)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Tiếng Romania"</string>
</resources>
diff --git a/packages/InputDevices/res/values-zh-rCN/strings.xml b/packages/InputDevices/res/values-zh-rCN/strings.xml
index 1f74d3436557..e3a8af367d70 100644
--- a/packages/InputDevices/res/values-zh-rCN/strings.xml
+++ b/packages/InputDevices/res/values-zh-rCN/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"黑山语(拉丁字母)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"塞尔维亚语(西里尔字母)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"黑山语(西里尔字母)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"罗马尼亚语"</string>
</resources>
diff --git a/packages/InputDevices/res/values-zh-rHK/strings.xml b/packages/InputDevices/res/values-zh-rHK/strings.xml
index 9c6864a7bec6..56681b8d3ece 100644
--- a/packages/InputDevices/res/values-zh-rHK/strings.xml
+++ b/packages/InputDevices/res/values-zh-rHK/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"蒙特內哥羅文 (拉丁)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"塞爾維亞文 (西里爾字母)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"蒙特內哥羅文 (西里爾字母)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"羅馬尼亞文"</string>
</resources>
diff --git a/packages/InputDevices/res/values-zh-rTW/strings.xml b/packages/InputDevices/res/values-zh-rTW/strings.xml
index f4159c983bb4..60c085bb2bac 100644
--- a/packages/InputDevices/res/values-zh-rTW/strings.xml
+++ b/packages/InputDevices/res/values-zh-rTW/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"蒙特內哥羅文 (拉丁字母)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"塞爾維亞文 (西里爾字母)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"蒙特內哥羅文 (西里爾字母)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"羅馬尼亞文"</string>
</resources>
diff --git a/packages/InputDevices/res/values-zu/strings.xml b/packages/InputDevices/res/values-zu/strings.xml
index ead5a4557901..66973333fa75 100644
--- a/packages/InputDevices/res/values-zu/strings.xml
+++ b/packages/InputDevices/res/values-zu/strings.xml
@@ -56,4 +56,5 @@
<string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"IsiMontenegrin (Latin)"</string>
<string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbian (Cyrillic)"</string>
<string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrin (Cyrillic)"</string>
+ <string name="keyboard_layout_romanian" msgid="8698989892731726903">"IsiRomanian"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-kn/strings.xml b/packages/PackageInstaller/res/values-kn/strings.xml
index f26ac2d0229a..4789f8bcc83a 100644
--- a/packages/PackageInstaller/res/values-kn/strings.xml
+++ b/packages/PackageInstaller/res/values-kn/strings.xml
@@ -91,7 +91,7 @@
<string name="manage_device_administrators" msgid="3092696419363842816">"ಸಾಧನದ ನಿರ್ವಹಣೆ ಆ್ಯಪ್‌ಗಳನ್ನು ನಿರ್ವಹಿಸಿ"</string>
<string name="manage_users" msgid="1243995386982560813">"ಬಳಕೆದಾರರನ್ನು ನಿರ್ವಹಿಸಿ"</string>
<string name="uninstall_failed_msg" msgid="2176744834786696012">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಅನ್ನು ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
- <string name="Parse_error_dlg_text" msgid="1661404001063076789">"ಪ್ಯಾಕೇಜ್ ಪಾರ್ಸ್ ಮಾಡುವಲ್ಲಿ ಸಮಸ್ಯೆ ಕಂಡುಬಂದಿದೆ."</string>
+ <string name="Parse_error_dlg_text" msgid="1661404001063076789">"ಪ್ಯಾಕೇಜ್ ಪಾರ್ಸ್ ಮಾಡುವಾಗ ಸಮಸ್ಯೆ ಕಂಡುಬಂದಿದೆ."</string>
<string name="message_staging" msgid="8032722385658438567">"ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲು ಸಿದ್ಧವಿರುವ ಆ್ಯಪ್…"</string>
<string name="app_name_unknown" msgid="6881210203354323926">"ಅಪರಿಚಿತ"</string>
<string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"ನಿಮ್ಮ ಸುರಕ್ಷತೆಯ ದೃಷ್ಟಿಯಿಂದ, ಈ ಮೂಲದಿಂದ ಬಂದಿರುವ ಅಪರಿಚಿತ ಆ್ಯಪ್‌ಗಳನ್ನು ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡಲು ಪ್ರಸ್ತುತ ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್‌ಗೆ ಅನುಮತಿಯಿಲ್ಲ. ನೀವು ಇದನ್ನು ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಬದಲಾಯಿಸಬಹುದು."</string>
diff --git a/packages/SettingsLib/CardPreference/res/drawable/settingslib_card_preference_background.xml b/packages/SettingsLib/CardPreference/res/drawable/settingslib_card_preference_background.xml
new file mode 100644
index 000000000000..1d57c1617495
--- /dev/null
+++ b/packages/SettingsLib/CardPreference/res/drawable/settingslib_card_preference_background.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+ <item>
+ <shape android:shape="rectangle">
+ <solid
+ android:color="@color/settingslib_materialColorSecondaryContainer" />
+ <corners
+ android:radius="@dimen/settingslib_expressive_radius_extralarge3" />
+ </shape>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/packages/SettingsLib/CardPreference/res/layout/settingslib_expressive_preference_card.xml b/packages/SettingsLib/CardPreference/res/layout/settingslib_expressive_preference_card.xml
index 9018baca79e7..4ce106e56822 100644
--- a/packages/SettingsLib/CardPreference/res/layout/settingslib_expressive_preference_card.xml
+++ b/packages/SettingsLib/CardPreference/res/layout/settingslib_expressive_preference_card.xml
@@ -14,9 +14,13 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.google.android.material.card.MaterialCardView
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- style="@style/SettingsLibCardStyle">
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingVertical="@dimen/settingslib_expressive_space_extrasmall4">
<LinearLayout
android:id="@+id/card_container"
@@ -24,10 +28,10 @@
android:layout_height="wrap_content"
android:baselineAligned="false"
android:minHeight="@dimen/settingslib_expressive_space_large3"
- android:paddingStart="@dimen/settingslib_expressive_space_small1"
- android:paddingEnd="@dimen/settingslib_expressive_space_small1"
+ android:paddingHorizontal="@dimen/settingslib_expressive_space_medium1"
android:orientation="horizontal"
- android:gravity="center_vertical">
+ android:gravity="center_vertical"
+ android:background="@drawable/settingslib_card_preference_background">
<LinearLayout
android:id="@+id/icon_frame"
@@ -35,15 +39,13 @@
android:layout_height="wrap_content"
android:minWidth="@dimen/settingslib_expressive_space_medium3"
android:minHeight="@dimen/settingslib_expressive_space_medium3"
- android:gravity="center"
- android:orientation="horizontal">
-
+ android:gravity="center">
<ImageView
android:id="@android:id/icon"
android:layout_width="@dimen/settingslib_expressive_space_medium3"
android:layout_height="@dimen/settingslib_expressive_space_medium3"
- android:scaleType="centerInside"/>
-
+ android:scaleType="centerInside"
+ android:importantForAccessibility="no"/>
</LinearLayout>
<LinearLayout
@@ -54,19 +56,16 @@
android:paddingHorizontal="@dimen/settingslib_expressive_space_small1"
android:paddingVertical="@dimen/settingslib_expressive_space_small2"
android:orientation="vertical">
-
<TextView
android:id="@android:id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:textAppearance="@style/TextAppearance.CardTitle.SettingsLib"/>
-
+ android:textAppearance="@style/TextAppearance.CardTitle.SettingsLib" />
<TextView
android:id="@android:id/summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:textAppearance="@style/TextAppearance.CardSummary.SettingsLib"/>
-
+ android:textAppearance="@style/TextAppearance.CardSummary.SettingsLib" />
</LinearLayout>
<ImageView
@@ -75,9 +74,9 @@
android:layout_height="@dimen/settingslib_expressive_space_medium4"
android:padding="@dimen/settingslib_expressive_space_extrasmall4"
android:layout_gravity="center"
+ android:contentDescription="@string/settingslib_dismiss_button_content_description"
android:src="@drawable/settingslib_expressive_icon_close"
- android:background="?android:attr/selectableItemBackground" />
+ android:tint="@color/settingslib_materialColorOnSecondary" />
</LinearLayout>
-
-</com.google.android.material.card.MaterialCardView> \ No newline at end of file
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SettingsLib/CardPreference/res/values/styles_expressive.xml b/packages/SettingsLib/CardPreference/res/values/styles_expressive.xml
index 287b13fa0d50..e7d4a0013896 100644
--- a/packages/SettingsLib/CardPreference/res/values/styles_expressive.xml
+++ b/packages/SettingsLib/CardPreference/res/values/styles_expressive.xml
@@ -18,11 +18,11 @@
<resources>
<style name="TextAppearance.CardTitle.SettingsLib"
parent="@style/TextAppearance.SettingsLib.TitleMedium.Emphasized">
- <item name="android:textColor">@color/settingslib_materialColorOnPrimary</item>
+ <item name="android:textColor">@color/settingslib_materialColorOnSecondaryContainer</item>
</style>
<style name="TextAppearance.CardSummary.SettingsLib"
parent="@style/TextAppearance.SettingsLib.LabelMedium">
- <item name="android:textColor">@color/settingslib_materialColorOnSecondary</item>
+ <item name="android:textColor">@color/settingslib_materialColorOnSecondaryContainer</item>
</style>
</resources> \ No newline at end of file
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
index f001fad69dc6..8b29b0044eea 100644
--- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
@@ -40,7 +40,6 @@ import com.android.settingslib.graph.proto.PreferenceProto
import com.android.settingslib.graph.proto.PreferenceProto.ActionTarget
import com.android.settingslib.graph.proto.PreferenceScreenProto
import com.android.settingslib.graph.proto.TextProto
-import com.android.settingslib.metadata.BooleanValue
import com.android.settingslib.metadata.FloatPersistentPreference
import com.android.settingslib.metadata.PersistentPreference
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
@@ -410,18 +409,20 @@ fun PreferenceMetadata.toProto(
val storage = metadata.storage(context)
value = preferenceValueProto {
when (metadata) {
- is BooleanValue -> storage.getBoolean(metadata.key)?.let { booleanValue = it }
is RangeValue -> storage.getInt(metadata.key)?.let { intValue = it }
is FloatPersistentPreference ->
storage.getFloat(metadata.key)?.let { floatValue = it }
else -> {}
}
+ when (metadata.valueType) {
+ Boolean::class.javaObjectType ->
+ storage.getBoolean(metadata.key)?.let { booleanValue = it }
+ }
}
}
if (flags.includeValueDescriptor()) {
valueDescriptor = preferenceValueDescriptorProto {
when (metadata) {
- is BooleanValue -> booleanType = true
is RangeValue -> rangeValue = rangeValueProto {
min = metadata.getMinValue(context)
max = metadata.getMaxValue(context)
@@ -430,6 +431,11 @@ fun PreferenceMetadata.toProto(
is FloatPersistentPreference -> floatType = true
else -> {}
}
+ if (metadata is PersistentPreference<*>) {
+ when (metadata.valueType) {
+ Boolean::class.javaObjectType -> booleanType = true
+ }
+ }
}
}
}
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt
index ea795542a5f6..47190648810a 100644
--- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt
@@ -26,7 +26,6 @@ import com.android.settingslib.ipc.ApiHandler
import com.android.settingslib.ipc.ApiPermissionChecker
import com.android.settingslib.ipc.IntMessageCodec
import com.android.settingslib.ipc.MessageCodec
-import com.android.settingslib.metadata.BooleanValue
import com.android.settingslib.metadata.PersistentPreference
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
import com.android.settingslib.metadata.PreferenceMetadata
@@ -146,7 +145,9 @@ class PreferenceSetterApiHandler(
val value = request.value
try {
if (value.hasBooleanValue()) {
- if (metadata !is BooleanValue) return PreferenceSetterResult.INVALID_REQUEST
+ if (metadata.valueType != Boolean::class.javaObjectType) {
+ return PreferenceSetterResult.INVALID_REQUEST
+ }
val booleanValue = value.booleanValue
val resultCode = metadata.checkWritePermit(booleanValue)
if (resultCode != PreferenceSetterResult.OK) return resultCode
diff --git a/packages/SettingsLib/IllustrationPreference/res/drawable/protection_background_tablet.xml b/packages/SettingsLib/IllustrationPreference/res/drawable/protection_background_tablet.xml
new file mode 100644
index 000000000000..31714b7ff902
--- /dev/null
+++ b/packages/SettingsLib/IllustrationPreference/res/drawable/protection_background_tablet.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item>
+ <shape android:shape="rectangle">
+ <solid android:color="@color/settingslib_protection_color"/>
+ <corners android:radius="28dp"/>
+ <size android:width="@dimen/settingslib_illustration_width_tablet"
+ android:height="@dimen/settingslib_illustration_height_tablet"/>
+ </shape>
+ </item>
+</layer-list>
diff --git a/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml b/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
index 0ae9c2674bc7..fcc2a04201dd 100644
--- a/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
+++ b/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
@@ -40,6 +40,15 @@
android:adjustViewBounds="true"
android:src="@drawable/protection_background"/>
+ <ImageView
+ android:id="@+id/background_view_tablet"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:adjustViewBounds="true"
+ android:src="@drawable/protection_background_tablet"
+ android:visibility="gone"/>
+
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottie_view"
android:layout_width="wrap_content"
diff --git a/packages/SettingsLib/IllustrationPreference/res/values/dimens.xml b/packages/SettingsLib/IllustrationPreference/res/values/dimens.xml
index fc273dc7403b..7b5012efd783 100644
--- a/packages/SettingsLib/IllustrationPreference/res/values/dimens.xml
+++ b/packages/SettingsLib/IllustrationPreference/res/values/dimens.xml
@@ -21,4 +21,7 @@
<dimen name="settingslib_illustration_width">412dp</dimen>
<dimen name="settingslib_illustration_height">300dp</dimen>
+
+ <dimen name="settingslib_illustration_width_tablet">498dp</dimen>
+ <dimen name="settingslib_illustration_height_tablet">362dp</dimen>
</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 bc4f1f942dc0..4b407c50bbd5 100644
--- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
@@ -72,6 +72,7 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
private OnBindListener mOnBindListener;
private boolean mLottieDynamicColor;
private CharSequence mContentDescription;
+ private boolean mIsTablet;
/**
* Interface to listen in on when {@link #onBindViewHolder(PreferenceViewHolder)} occurs.
@@ -127,8 +128,17 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
final FrameLayout illustrationFrame = (FrameLayout) holder.findViewById(
R.id.illustration_frame);
- final ImageView backgroundView =
+ ImageView backgroundView =
(ImageView) holder.findViewById(R.id.background_view);
+ ImageView backgroundViewTablet =
+ (ImageView) holder.findViewById(R.id.background_view_tablet);
+
+ backgroundView.setVisibility(mIsTablet ? View.GONE : View.VISIBLE);
+ backgroundViewTablet.setVisibility(mIsTablet ? View.VISIBLE : View.GONE);
+ if (mIsTablet) {
+ backgroundView = backgroundViewTablet;
+ }
+
final FrameLayout middleGroundLayout =
(FrameLayout) holder.findViewById(R.id.middleground_layout);
final LottieAnimationView illustrationView =
@@ -413,7 +423,7 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
final Resources res = backgroundView.getResources();
final int frameWidth = res.getDimensionPixelSize(R.dimen.settingslib_illustration_width);
final int frameHeight = res.getDimensionPixelSize(R.dimen.settingslib_illustration_height);
- final int restrictedMaxHeight = Math.min(mMaxHeight, frameHeight);
+ final int restrictedMaxHeight = mMaxHeight;
backgroundView.setMaxHeight(restrictedMaxHeight);
illustrationView.setMaxHeight(restrictedMaxHeight);
@@ -505,5 +515,11 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
a.recycle();
}
+ mIsTablet = SettingsThemeHelper.isExpressiveTheme(context)
+ && SettingsThemeHelper.isTablet(context);
+ if (mIsTablet) {
+ setMaxHeight(context.getResources().getDimensionPixelSize(
+ R.dimen.settingslib_illustration_height_tablet));
+ }
}
}
diff --git a/packages/SettingsLib/Metadata/processor/src/com/android/settingslib/metadata/PreferenceScreenAnnotationProcessor.kt b/packages/SettingsLib/Metadata/processor/src/com/android/settingslib/metadata/PreferenceScreenAnnotationProcessor.kt
index 14e3b87cf325..38b641336547 100644
--- a/packages/SettingsLib/Metadata/processor/src/com/android/settingslib/metadata/PreferenceScreenAnnotationProcessor.kt
+++ b/packages/SettingsLib/Metadata/processor/src/com/android/settingslib/metadata/PreferenceScreenAnnotationProcessor.kt
@@ -114,15 +114,7 @@ class PreferenceScreenAnnotationProcessor : AbstractProcessor() {
private fun generateCode(outputPkg: String, outputClass: String, outputFun: String) {
// sort by screen keys to make the output deterministic and naturally fit to FixedArrayMap
screens.sort()
- val javaFileObject =
- try {
- processingEnv.filer.createSourceFile("$outputPkg.$outputClass")
- } catch (e: Exception) {
- // quick fix: gradle runs this processor twice unexpectedly
- warn("cannot createSourceFile: $e")
- return
- }
- javaFileObject.openWriter().use {
+ processingEnv.filer.createSourceFile("$outputPkg.$outputClass").openWriter().use {
it.write("package $outputPkg;\n\n")
it.write("import $PACKAGE.FixedArrayMap;\n")
it.write("import $PACKAGE.FixedArrayMap.OrderedInitializer;\n")
diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt
index 83725aaec377..4cc65815a78a 100644
--- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt
+++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt
@@ -79,6 +79,14 @@ annotation class SensitivityLevel {
interface PersistentPreference<T> {
/**
+ * The value type the preference is associated with.
+ *
+ * TODO(b/388167302): Remove the default implementation once all subclasses are migrated.
+ */
+ val valueType: Class<T>?
+ get() = null
+
+ /**
* Returns the key-value storage of the preference.
*
* The default implementation returns the storage provided by
@@ -143,15 +151,6 @@ sealed interface ValueDescriptor {
fun isValidValue(context: Context, index: Int): Boolean
}
-/**
- * A boolean type value.
- *
- * A zero value means `False`, otherwise it is `True`.
- */
-interface BooleanValue : ValueDescriptor {
- override fun isValidValue(context: Context, index: Int) = true
-}
-
/** Value falls into a given array. */
interface DiscreteValue<T> : ValueDescriptor {
@get:ArrayRes val values: Int
@@ -221,5 +220,11 @@ interface RangeValue : ValueDescriptor {
index in getMinValue(context)..getMaxValue(context)
}
+/** A persistent preference that has a boolean value. */
+interface BooleanPreference : PersistentPreference<Boolean> {
+ override val valueType: Class<Boolean>
+ get() = Boolean::class.javaObjectType
+}
+
/** A persistent preference that has a float value. */
interface FloatPersistentPreference : PersistentPreference<Float>
diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceTypes.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceTypes.kt
index 87bd261bf4bd..b79a0c4f6381 100644
--- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceTypes.kt
+++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceTypes.kt
@@ -19,7 +19,7 @@ package com.android.settingslib.metadata
import androidx.annotation.StringRes
/** Common base class for preferences that have two selectable states and save a boolean value. */
-interface TwoStatePreference : PreferenceMetadata, PersistentPreference<Boolean>, BooleanValue
+interface TwoStatePreference : PreferenceMetadata, BooleanPreference
/** A preference that provides a two-state toggleable option. */
open class SwitchPreference
diff --git a/packages/SettingsLib/SearchWidget/res/values-as/strings.xml b/packages/SettingsLib/SearchWidget/res/values-as/strings.xml
index 8d95131e0e15..8c1bd4024595 100644
--- a/packages/SettingsLib/SearchWidget/res/values-as/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-as/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="search_menu" msgid="1914043873178389845">"সন্ধান সম্পৰ্কীয় ছেটিং"</string>
+ <string name="search_menu" msgid="1914043873178389845">"ছেটিঙত সন্ধান কৰক"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-es-rUS/strings.xml b/packages/SettingsLib/SearchWidget/res/values-es-rUS/strings.xml
index d38510189507..db02f002b935 100644
--- a/packages/SettingsLib/SearchWidget/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-es-rUS/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="search_menu" msgid="1914043873178389845">"Buscar configuración"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Buscar en Configuración"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-mk/strings.xml b/packages/SettingsLib/SearchWidget/res/values-mk/strings.xml
index a1bb54e07260..258208473ade 100644
--- a/packages/SettingsLib/SearchWidget/res/values-mk/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-mk/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="search_menu" msgid="1914043873178389845">"Пребарување низ поставките"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Пребарувајте низ поставките"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-pa/strings.xml b/packages/SettingsLib/SearchWidget/res/values-pa/strings.xml
index 09a285b7452f..97497c18c621 100644
--- a/packages/SettingsLib/SearchWidget/res/values-pa/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-pa/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="search_menu" msgid="1914043873178389845">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਖੋਜੋ"</string>
+ <string name="search_menu" msgid="1914043873178389845">"ਸੈਟਿੰਗਾਂ ਖੋਜੋ"</string>
</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/themes.xml b/packages/SettingsLib/SettingsTheme/res/values-v35/themes.xml
index b6e80c784f10..dc5c9b297181 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v35/themes.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v35/themes.xml
@@ -18,7 +18,7 @@
<resources>
<style name="Theme.SettingsBase_v35" parent="Theme.SettingsBase_v33" >
<item name="android:colorAccent">@color/settingslib_materialColorPrimary</item>
- <item name="android:colorBackground">@color/settingslib_materialColorSurfaceContainer</item>
+ <item name="android:colorBackground">@color/settingslib_materialColorSurfaceContainerLowest</item>
<item name="android:textColorPrimary">@color/settingslib_materialColorOnSurface</item>
<item name="android:textColorSecondary">@color/settingslib_text_color_secondary</item>
<item name="android:textColorTertiary">@color/settingslib_materialColorOutline</item>
diff --git a/packages/SettingsLib/SettingsTheme/res/values/strings.xml b/packages/SettingsLib/SettingsTheme/res/values/strings.xml
index c36dcb88b9fe..f3f077edc91d 100644
--- a/packages/SettingsLib/SettingsTheme/res/values/strings.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/strings.xml
@@ -21,4 +21,6 @@
<string name="settingslib_expressive_text_expand">Expand</string>
<!-- text of button to indicate user the textView is collapsable [CHAR LIMIT=NONE] -->
<string name="settingslib_expressive_text_collapse">Collapse</string>
+ <!-- Content description of the dismiss button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="settingslib_dismiss_button_content_description">Dismiss</string>
</resources> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt
index 74f5441f6760..6794cd0e30a2 100644
--- a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt
+++ b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt
@@ -21,6 +21,7 @@ import android.os.Build
object SettingsThemeHelper {
private const val IS_EXPRESSIVE_DESIGN_ENABLED = "is_expressive_design_enabled"
+ private const val RO_BUILD_CHARACTERISTICS = "ro.build.characteristics"
private var expressiveThemeState: ExpressiveThemeState = ExpressiveThemeState.UNKNOWN
enum class ExpressiveThemeState {
@@ -41,6 +42,12 @@ object SettingsThemeHelper {
return expressiveThemeState == ExpressiveThemeState.ENABLED
}
+ @JvmStatic
+ fun isTablet(context: Context): Boolean {
+ val result = getPropString(context, RO_BUILD_CHARACTERISTICS, "").split(',')
+ return result.contains("tablet")
+ }
+
private fun tryInit(context: Context) {
if (expressiveThemeState != ExpressiveThemeState.UNKNOWN) {
return
@@ -73,4 +80,19 @@ object SettingsThemeHelper {
def
}
}
+
+ private fun getPropString(context: Context, property: String, def: String): String {
+ return try {
+ val systemProperties = context.classLoader.loadClass("android.os.SystemProperties")
+
+ val paramTypes =
+ arrayOf<Class<*>?>(String::class.java, String::class.java)
+ val get = systemProperties.getMethod("get", *paramTypes)
+ get.invoke(systemProperties, property, def) as String
+ } catch (iae: IllegalArgumentException) {
+ throw iae
+ } catch (exception: Exception) {
+ def
+ }
+ }
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
index 4a7937a3c2ac..e5868d0f1f71 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
@@ -51,12 +51,14 @@ import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewmodel.compose.viewModel
+import com.android.settingslib.spa.framework.compose.contentDescription
import com.android.settingslib.spa.framework.compose.hideKeyboardAction
import com.android.settingslib.spa.framework.compose.horizontalValues
import com.android.settingslib.spa.framework.theme.SettingsOpacity
@@ -175,12 +177,15 @@ private fun SearchBox(query: TextFieldValue, onQueryChange: (TextFieldValue) ->
onValueChange = onQueryChange,
modifier = Modifier
.fillMaxWidth()
- .focusRequester(focusRequester),
+ .focusRequester(focusRequester)
+ .contentDescription(stringResource(R.string.abc_search_hint)),
textStyle = textStyle,
placeholder = {
Text(
text = stringResource(R.string.abc_search_hint),
- modifier = Modifier.alpha(SettingsOpacity.Hint),
+ modifier = Modifier
+ .alpha(SettingsOpacity.Hint)
+ .clearAndSetSemantics {},
style = textStyle,
)
},
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt
index 826a0d461c8c..3d73b065751f 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt
@@ -130,7 +130,7 @@ class SearchScaffoldTest {
).performClick()
}
- private fun onSearchHint() = composeTestRule.onNodeWithText(
+ private fun onSearchHint() = composeTestRule.onNodeWithContentDescription(
context.getString(R.string.abc_search_hint)
)
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BytesFormatter.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BytesFormatter.kt
index 5b7e2a86135a..e6cc8a80ee38 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BytesFormatter.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BytesFormatter.kt
@@ -24,6 +24,7 @@ import android.icu.text.NumberFormat
import android.icu.text.UnicodeSet
import android.icu.text.UnicodeSetSpanner
import android.icu.util.Measure
+import android.text.BidiFormatter
import android.text.format.Formatter
import android.text.format.Formatter.RoundedBytesResult
import java.math.BigDecimal
@@ -40,11 +41,17 @@ class BytesFormatter(resources: Resources) {
constructor(context: Context) : this(context.resources)
private val locale = resources.configuration.locales[0]
+ private val bidiFormatter = BidiFormatter.getInstance(locale)
fun format(bytes: Long, useCase: UseCase): String {
val rounded = RoundedBytesResult.roundBytes(bytes, useCase.flag)
val numberFormatter = getNumberFormatter(rounded.fractionDigits)
- return numberFormatter.formatRoundedBytesResult(rounded)
+ val formattedString = numberFormatter.formatRoundedBytesResult(rounded)
+ return if (useCase == UseCase.FileSize) {
+ formattedString.bidiWrap()
+ } else {
+ formattedString
+ }
}
fun formatWithUnits(bytes: Long, useCase: UseCase): Result {
@@ -74,6 +81,14 @@ class BytesFormatter(resources: Resources) {
}
}
+ /** Wraps the source string in bidi formatting characters in RTL locales. */
+ private fun String.bidiWrap(): String =
+ if (bidiFormatter.isRtlContext) {
+ bidiFormatter.unicodeWrap(this)
+ } else {
+ this
+ }
+
private companion object {
fun String.removeFirst(removed: String): String =
SPACES_AND_CONTROLS.trim(replaceFirst(removed, "")).toString()
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppStorageRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppStorageRepository.kt
new file mode 100644
index 000000000000..6fd470c1e7aa
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppStorageRepository.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.settingslib.spaprivileged.model.app
+
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.util.Log
+import com.android.settingslib.spaprivileged.framework.common.BytesFormatter
+import com.android.settingslib.spaprivileged.framework.common.storageStatsManager
+
+/** A repository interface for accessing and formatting app storage information. */
+interface AppStorageRepository {
+ /**
+ * Formats the size of an application into a human-readable string.
+ *
+ * This function retrieves the total size of the application, including APK file and its
+ * associated data.
+ *
+ * This function takes an [ApplicationInfo] object as input and returns a formatted string
+ * representing the size of the application. The size is formatted in units like kB, MB, GB,
+ * etc.
+ *
+ * @param app The [ApplicationInfo] object representing the application.
+ * @return A formatted string representing the size of the application.
+ */
+ fun formatSize(app: ApplicationInfo): String
+
+ /**
+ * Formats the size about an application into a human-readable string.
+ *
+ * @param sizeBytes The size in bytes to format.
+ * @return A formatted string representing the size about application.
+ */
+ fun formatSizeBytes(sizeBytes: Long): String
+
+ /**
+ * Calculates the size of an application in bytes.
+ *
+ * This function retrieves the total size of the application, including APK file and its
+ * associated data.
+ *
+ * @param app The [ApplicationInfo] object representing the application.
+ * @return The total size of the application in bytes, or null if the size could not be
+ * determined.
+ */
+ fun calculateSizeBytes(app: ApplicationInfo): Long?
+}
+
+class AppStorageRepositoryImpl(context: Context) : AppStorageRepository {
+ private val storageStatsManager = context.storageStatsManager
+ private val bytesFormatter = BytesFormatter(context)
+
+ override fun formatSize(app: ApplicationInfo): String {
+ val sizeBytes = calculateSizeBytes(app)
+ return if (sizeBytes != null) formatSizeBytes(sizeBytes) else ""
+ }
+
+ override fun formatSizeBytes(sizeBytes: Long): String =
+ bytesFormatter.format(sizeBytes, BytesFormatter.UseCase.FileSize)
+
+ override fun calculateSizeBytes(app: ApplicationInfo): Long? =
+ try {
+ val stats =
+ storageStatsManager.queryStatsForPackage(
+ app.storageUuid,
+ app.packageName,
+ app.userHandle,
+ )
+ stats.codeBytes + stats.dataBytes
+ } catch (e: Exception) {
+ Log.w(TAG, "Failed to query stats", e)
+ null
+ }
+
+ companion object {
+ private const val TAG = "AppStorageRepository"
+ }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt
index 7a4f81cc1321..7c98e9cd813b 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt
@@ -16,42 +16,30 @@
package com.android.settingslib.spaprivileged.template.app
-import android.content.Context
import android.content.pm.ApplicationInfo
-import android.text.format.Formatter
-import android.util.Log
+import androidx.annotation.VisibleForTesting
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
-import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.settingslib.spaprivileged.framework.common.storageStatsManager
+import com.android.settingslib.spa.framework.compose.rememberContext
import com.android.settingslib.spaprivileged.framework.compose.placeholder
-import com.android.settingslib.spaprivileged.model.app.userHandle
+import com.android.settingslib.spaprivileged.model.app.AppStorageRepository
+import com.android.settingslib.spaprivileged.model.app.AppStorageRepositoryImpl
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
-private const val TAG = "AppStorageSize"
-
@Composable
-fun ApplicationInfo.getStorageSize(): State<String> {
- val context = LocalContext.current
- return remember(this) {
- flow {
- val sizeBytes = calculateSizeBytes(context)
- this.emit(if (sizeBytes != null) Formatter.formatFileSize(context, sizeBytes) else "")
- }.flowOn(Dispatchers.IO)
- }.collectAsStateWithLifecycle(initialValue = placeholder())
-}
+fun ApplicationInfo.getStorageSize(): State<String> =
+ getStorageSize(rememberContext(::AppStorageRepositoryImpl))
-fun ApplicationInfo.calculateSizeBytes(context: Context): Long? {
- val storageStatsManager = context.storageStatsManager
- return try {
- val stats = storageStatsManager.queryStatsForPackage(storageUuid, packageName, userHandle)
- stats.codeBytes + stats.dataBytes
- } catch (e: Exception) {
- Log.w(TAG, "Failed to query stats: $e")
- null
- }
+@VisibleForTesting
+@Composable
+fun ApplicationInfo.getStorageSize(appStorageRepository: AppStorageRepository): State<String> {
+ val app = this
+ return remember(app) {
+ flow { emit(appStorageRepository.formatSize(app)) }.flowOn(Dispatchers.Default)
+ }
+ .collectAsStateWithLifecycle(initialValue = placeholder())
}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppStorageRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppStorageRepositoryTest.kt
new file mode 100644
index 000000000000..e8ec974bb0b8
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppStorageRepositoryTest.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.settingslib.spaprivileged.model.app
+
+import android.app.usage.StorageStats
+import android.app.usage.StorageStatsManager
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager.NameNotFoundException
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spaprivileged.framework.common.storageStatsManager
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.doThrow
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.stub
+import java.util.UUID
+
+@RunWith(AndroidJUnit4::class)
+class AppStorageRepositoryTest {
+ private val app = ApplicationInfo().apply { storageUuid = UUID.randomUUID() }
+
+ private val mockStorageStatsManager =
+ mock<StorageStatsManager> {
+ on { queryStatsForPackage(app.storageUuid, app.packageName, app.userHandle) } doReturn
+ STATS
+ }
+
+ private val context: Context =
+ spy(ApplicationProvider.getApplicationContext()) {
+ on { storageStatsManager } doReturn mockStorageStatsManager
+ }
+
+ private val repository = AppStorageRepositoryImpl(context)
+
+ @Test
+ fun calculateSizeBytes() {
+ val sizeBytes = repository.calculateSizeBytes(app)
+
+ assertThat(sizeBytes).isEqualTo(120)
+ }
+
+ @Test
+ fun formatSize() {
+ val fileSize = repository.formatSize(app)
+
+ assertThat(fileSize).isEqualTo("120 byte")
+ }
+
+ @Test
+ fun formatSize_throwException() {
+ mockStorageStatsManager.stub {
+ on { queryStatsForPackage(app.storageUuid, app.packageName, app.userHandle) } doThrow
+ NameNotFoundException()
+ }
+
+ val fileSize = repository.formatSize(app)
+
+ assertThat(fileSize).isEqualTo("")
+ }
+
+ @Test
+ fun formatSizeBytes() {
+ val fileSize = repository.formatSizeBytes(120)
+
+ assertThat(fileSize).isEqualTo("120 byte")
+ }
+
+ companion object {
+ private val STATS =
+ StorageStats().apply {
+ codeBytes = 100
+ dataBytes = 20
+ }
+ }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt
index 60f3d0ce1be3..4f42c8254c39 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt
@@ -16,98 +16,37 @@
package com.android.settingslib.spaprivileged.template.app
-import android.app.usage.StorageStats
-import android.app.usage.StorageStatsManager
-import android.content.Context
import android.content.pm.ApplicationInfo
-import android.content.pm.PackageManager.NameNotFoundException
-import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.framework.compose.stateOf
-import com.android.settingslib.spaprivileged.framework.common.storageStatsManager
-import com.android.settingslib.spaprivileged.model.app.userHandle
-import java.util.UUID
-import org.junit.Before
+import com.android.settingslib.spaprivileged.model.app.AppStorageRepository
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Spy
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
-import org.mockito.kotlin.whenever
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import java.util.UUID
@RunWith(AndroidJUnit4::class)
class AppStorageSizeTest {
- @get:Rule
- val mockito: MockitoRule = MockitoJUnit.rule()
-
- @get:Rule
- val composeTestRule = createComposeRule()
+ @get:Rule val composeTestRule = createComposeRule()
- @Spy
- private val context: Context = ApplicationProvider.getApplicationContext()
-
- @Mock
- private lateinit var storageStatsManager: StorageStatsManager
-
- private val app = ApplicationInfo().apply {
- storageUuid = UUID.randomUUID()
- }
+ private val app = ApplicationInfo().apply { storageUuid = UUID.randomUUID() }
- @Before
- fun setUp() {
- whenever(context.storageStatsManager).thenReturn(storageStatsManager)
- whenever(
- storageStatsManager.queryStatsForPackage(
- app.storageUuid,
- app.packageName,
- app.userHandle,
- )
- ).thenReturn(STATS)
- }
+ private val mockAppStorageRepository =
+ mock<AppStorageRepository> { on { formatSize(app) } doReturn SIZE }
@Test
fun getStorageSize() {
var storageSize = stateOf("")
- composeTestRule.setContent {
- CompositionLocalProvider(LocalContext provides context) {
- storageSize = app.getStorageSize()
- }
- }
-
- composeTestRule.waitUntil { storageSize.value == "120 B" }
- }
-
- @Test
- fun getStorageSize_throwException() {
- var storageSize = stateOf("Computing")
- whenever(
- storageStatsManager.queryStatsForPackage(
- app.storageUuid,
- app.packageName,
- app.userHandle,
- )
- ).thenThrow(NameNotFoundException())
-
- composeTestRule.setContent {
- CompositionLocalProvider(LocalContext provides context) {
- storageSize = app.getStorageSize()
- }
- }
+ composeTestRule.setContent { storageSize = app.getStorageSize(mockAppStorageRepository) }
- composeTestRule.waitUntil { storageSize.value == "" }
+ composeTestRule.waitUntil { storageSize.value == SIZE }
}
- companion object {
- private val STATS = StorageStats().apply {
- codeBytes = 100
- dataBytes = 20
- cacheBytes = 3
- }
+ private companion object {
+ const val SIZE = "120 kB"
}
}
diff --git a/packages/SettingsLib/ZeroStatePreference/Android.bp b/packages/SettingsLib/ZeroStatePreference/Android.bp
index 4fc00bdbfee0..0949e2c75c55 100644
--- a/packages/SettingsLib/ZeroStatePreference/Android.bp
+++ b/packages/SettingsLib/ZeroStatePreference/Android.bp
@@ -29,5 +29,6 @@ android_library {
min_sdk_version: "28",
apex_available: [
"//apex_available:platform",
+ "com.android.healthfitness",
],
}
diff --git a/packages/SettingsLib/ZeroStatePreference/res/layout/settingslib_expressive_preference_zerostate.xml b/packages/SettingsLib/ZeroStatePreference/res/layout/settingslib_expressive_preference_zerostate.xml
index c0b195cc1f74..ae3f1dde8a3a 100644
--- a/packages/SettingsLib/ZeroStatePreference/res/layout/settingslib_expressive_preference_zerostate.xml
+++ b/packages/SettingsLib/ZeroStatePreference/res/layout/settingslib_expressive_preference_zerostate.xml
@@ -17,7 +17,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical">
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index bbe08f254283..d94450b1cabd 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -219,3 +219,13 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "adopt_primary_group_management_api"
+ namespace: "cross_device_experiences"
+ description: "Adopt Bluetooth LE broadcast primary group management APIs"
+ bug: "381946931"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 0c71a2195538..bf039adf35e9 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -64,7 +64,7 @@
<string name="connected_via_network_scorer" msgid="7665725527352893558">"‏מחובר אוטומטית דרך %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"מחובר אוטומטית דרך ספק של דירוג רשת"</string>
<string name="connected_via_app" msgid="3532267661404276584">"מחוברת באמצעות <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="tap_to_sign_up" msgid="5356397741063740395">"יש להקיש כדי להירשם"</string>
+ <string name="tap_to_sign_up" msgid="5356397741063740395">"יש ללחוץ כדי להירשם"</string>
<string name="wifi_connected_no_internet" msgid="5087420713443350646">"אין אינטרנט"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"‏לא ניתן לגשת לשרת DNS הפרטי"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"חיבור מוגבל"</string>
@@ -74,7 +74,7 @@
<string name="osu_opening_provider" msgid="4318105381295178285">"מתבצעת פתיחה של <xliff:g id="PASSPOINTPROVIDER">%1$s</xliff:g>"</string>
<string name="osu_connect_failed" msgid="9107873364807159193">"לא ניתן היה להתחבר"</string>
<string name="osu_completing_sign_up" msgid="8412636665040390901">"מתבצעת השלמה של ההרשמה…"</string>
- <string name="osu_sign_up_failed" msgid="5605453599586001793">"לא ניתן היה להשלים את ההרשמה. יש להקיש כדי לנסות שוב."</string>
+ <string name="osu_sign_up_failed" msgid="5605453599586001793">"לא ניתן היה להשלים את ההרשמה. יש ללחוץ כדי לנסות שוב."</string>
<string name="osu_sign_up_complete" msgid="7640183358878916847">"תהליך ההרשמה הסתיים. בתהליך התחברות…"</string>
<string name="speed_label_slow" msgid="6069917670665664161">"איטית"</string>
<string name="speed_label_okay" msgid="1253594383880810424">"אישור"</string>
@@ -279,7 +279,7 @@
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"‏יש להתחבר לרשת Wi-Fi"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"‏adb, ניפוי באגים, פיתוח"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"קיצור דרך לדוח באגים"</string>
- <string name="bugreport_in_power_summary" msgid="1885529649381831775">"הצגת לחצן ליצירת דוח על באג בתפריט ההפעלה"</string>
+ <string name="bugreport_in_power_summary" msgid="1885529649381831775">"הצגת כפתור ליצירת דוח על באג בתפריט ההפעלה"</string>
<string name="keep_screen_on" msgid="1187161672348797558">"ללא כניסה למצב שינה"</string>
<string name="keep_screen_on_summary" msgid="1510731514101925829">"המסך לעולם לא יהיה במצב שינה במהלך טעינה"</string>
<string name="bt_hci_snoop_log" msgid="7291287955649081448">"‏הפעלת Snoop Log של Bluetooth HCI"</string>
@@ -380,8 +380,8 @@
<string name="strict_mode_summary" msgid="1838248687233554654">"‏המסך יהבהב כשאפליקציות יבצעו פעולות ארוכות ב-thread הראשי"</string>
<string name="pointer_location" msgid="7516929526199520173">"מיקום מצביע"</string>
<string name="pointer_location_summary" msgid="957120116989798464">"שכבת-על של המסך המציגה את נתוני המגע הנוכחיים"</string>
- <string name="show_touches" msgid="8437666942161289025">"הצגת הקשות"</string>
- <string name="show_touches_summary" msgid="3692861665994502193">"הצגת משוב ויזואלי להקשות"</string>
+ <string name="show_touches" msgid="8437666942161289025">"הצגת לחיצות"</string>
+ <string name="show_touches_summary" msgid="3692861665994502193">"הצגת משוב ויזואלי ללחיצות"</string>
<string name="show_key_presses" msgid="6360141722735900214">"הצגת לחיצות המקשים"</string>
<string name="show_key_presses_summary" msgid="725387457373015024">"הצגת משוב חזותי עבור לחיצות פיזיות על מקשים"</string>
<string name="touchpad_visualizer" msgid="3707916068870825115">"הצגת הקלט של לוח המגע"</string>
@@ -440,7 +440,7 @@
<string name="enable_freeform_support" msgid="7599125687603914253">"הפעלת מצב חופשי (חלונות צפים)"</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>
+ <string name="local_backup_password_summary_change" msgid="1707357670383995567">"יש ללחוץ כדי לשנות או להסיר את הסיסמה לגיבויים מלאים בשולחן העבודה"</string>
<string name="local_backup_password_toast_success" msgid="4891666204428091604">"הוגדרה סיסמת גיבוי חדשה"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="2994718182129097733">"הסיסמה החדשה והאישור אינם תואמים"</string>
<string name="local_backup_password_toast_validation_failure" msgid="714669442363647122">"הגדרת סיסמת גיבוי נכשלה"</string>
@@ -456,8 +456,8 @@
<item msgid="1282170165150762976">"צבעים מותאמים באופן אופטימלי לתוכן דיגיטלי"</item>
</string-array>
<string name="inactive_apps_title" msgid="5372523625297212320">"אפליקציות בהמתנה"</string>
- <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"אפליקציה לא פעילה. יש להקיש כדי להחליף מצב."</string>
- <string name="inactive_app_active_summary" msgid="8047630990208722344">"אפליקציה פעילה. יש להקיש כדי להחליף מצב."</string>
+ <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"אפליקציה לא פעילה. יש ללחוץ כדי להחליף מצב."</string>
+ <string name="inactive_app_active_summary" msgid="8047630990208722344">"אפליקציה פעילה. יש ללחוץ כדי להחליף מצב."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"אפליקציה במצב המתנה:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="transcode_settings_title" msgid="2581975870429850549">"הגדרות של המרת קידוד למדיה"</string>
<string name="transcode_user_control" msgid="6176368544817731314">"ביטול ברירות המחדל של המרת קידוד"</string>
diff --git a/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java b/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java
index fa43915deb6a..5b25d0dc04e1 100644
--- a/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java
+++ b/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java
@@ -35,7 +35,6 @@ import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedOptions;
-import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
@@ -48,7 +47,6 @@ import javax.tools.Diagnostic.Kind;
* Annotation processor for {@link SearchIndexable} that generates {@link SearchIndexableResources}
* subclasses.
*/
-@SupportedSourceVersion(SourceVersion.RELEASE_17)
@SupportedOptions(IndexableProcessor.PACKAGE_KEY)
@SupportedAnnotationTypes({"com.android.settingslib.search.SearchIndexable"})
public class IndexableProcessor extends AbstractProcessor {
@@ -69,6 +67,11 @@ public class IndexableProcessor extends AbstractProcessor {
private boolean mRanOnce;
@Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latestSupported();
+ }
+
+ @Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnvironment) {
if (mRanOnce) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 1998d0c6721c..2b8e20ffc71a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -10,6 +10,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.content.res.ColorStateList;
@@ -32,6 +33,7 @@ import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
import android.net.TetheringManager;
+import android.net.Uri;
import android.net.vcn.VcnUtils;
import android.net.wifi.WifiInfo;
import android.os.BatteryManager;
@@ -79,11 +81,14 @@ public class Utils {
@VisibleForTesting
static final String STORAGE_MANAGER_ENABLED_PROPERTY = "ro.storage_manager.enabled";
+ private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
+
private static Signature[] sSystemSignature;
private static String sPermissionControllerPackageName;
private static String sServicesSystemSharedLibPackageName;
private static String sSharedSystemSharedLibPackageName;
private static String sDefaultWebViewPackageName;
+ private static String sPackageInstallerPackageName;
static final int[] WIFI_PIE = {
com.android.internal.R.drawable.ic_wifi_signal_0,
@@ -496,9 +501,29 @@ public class Utils {
|| packageName.equals(sSharedSystemSharedLibPackageName)
|| packageName.equals(PrintManager.PRINT_SPOOLER_PACKAGE_NAME)
|| packageName.equals(getDefaultWebViewPackageName(pm))
+ || packageName.equals(getPackageInstallerPackageName(pm))
|| isDeviceProvisioningPackage(resources, packageName);
}
+ /** Return the package name of the installer */
+ private static String getPackageInstallerPackageName(PackageManager pm) {
+ if (sPackageInstallerPackageName != null) {
+ return sPackageInstallerPackageName;
+ }
+ final Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ intent.setDataAndType(Uri.parse("content://com.example/foo.apk"), PACKAGE_MIME_TYPE);
+ final List<ResolveInfo> matches =
+ pm.queryIntentActivities(intent, PackageManager.GET_META_DATA);
+ if (matches.size() == 1) {
+ final ResolveInfo resolveInfo = matches.get(0);
+ if (resolveInfo.activityInfo.applicationInfo.isPrivilegedApp()) {
+ sPackageInstallerPackageName = resolveInfo.getComponentInfo().packageName;
+ }
+ }
+ return sPackageInstallerPackageName;
+ }
+
/**
* Returns {@code true} if the supplied package is the device provisioning app. Otherwise,
* returns {@code false}.
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
index 4b7cb36f2753..bf86911ee683 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -134,6 +134,8 @@ public class CsipDeviceManager {
// Do nothing if GroupId has been assigned
if (!isValidGroupId(cachedDevice.getGroupId())) {
final int newGroupId = getBaseGroupId(cachedDevice.getDevice());
+ log("updateCsipDevices: propose new group id " + newGroupId + " for device "
+ + cachedDevice.getDevice());
// Do nothing if there is no GroupId on Bluetooth device
if (isValidGroupId(newGroupId)) {
cachedDevice.setGroupId(newGroupId);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 7c24df9e9019..ff5e9e657213 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -358,6 +358,9 @@ public class LocalBluetoothProfileManager {
&& mProfile instanceof CsipSetCoordinatorProfile;
if (isAshaProfile && (newState == BluetoothProfile.STATE_CONNECTED)) {
+ if (DEBUG) {
+ Log.d(TAG, "onReceive, hearing aid profile connected, check hisyncid");
+ }
// Check if the HiSyncID has being initialized
if (cachedDevice.getHiSyncId() == BluetoothHearingAid.HI_SYNC_ID_INVALID) {
long newHiSyncId = getHearingAidProfile().getHiSyncId(cachedDevice.getDevice());
@@ -375,7 +378,9 @@ public class LocalBluetoothProfileManager {
}
if (isHapClientOrLeAudioProfile && newState == BluetoothProfile.STATE_CONNECTED) {
-
+ if (DEBUG) {
+ Log.d(TAG, "onReceive, hap/lea profile connected, check hearing aid info");
+ }
// Checks if both profiles are connected to the device. Hearing aid info need
// to be retrieved from these profiles separately.
if (cachedDevice.isConnectedLeAudioHearingAidDevice()) {
@@ -389,10 +394,16 @@ public class LocalBluetoothProfileManager {
}
if (isCsipProfile && (newState == BluetoothProfile.STATE_CONNECTED)) {
+ if (DEBUG) {
+ Log.d(TAG, "onReceive, csip profile connected, check group id");
+ }
// Check if the GroupID has being initialized
if (cachedDevice.getGroupId() == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
final Map<Integer, ParcelUuid> groupIdMap = getCsipSetCoordinatorProfile()
.getGroupUuidMapByDevice(cachedDevice.getDevice());
+ if (DEBUG) {
+ Log.d(TAG, "csip group uuid map = " + groupIdMap);
+ }
if (groupIdMap != null) {
for (Map.Entry<Integer, ParcelUuid> entry: groupIdMap.entrySet()) {
if (entry.getValue().equals(BluetoothUuid.CAP)) {
@@ -431,6 +442,9 @@ public class LocalBluetoothProfileManager {
mProfile.getProfileId());
}
if (needDispatchProfileConnectionState) {
+ if (DEBUG) {
+ Log.d(TAG, "needDispatchProfileConnectionState");
+ }
cachedDevice.refresh();
mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState,
mProfile.getProfileId());
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
index 84afb9f7a7e2..a1cf409733fb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
@@ -37,10 +37,10 @@ public abstract class AbstractPreferenceController {
private static final String TAG = "AbstractPrefController";
- protected final Context mContext;
+ protected final @NonNull Context mContext;
private final DevicePolicyManager mDevicePolicyManager;
- public AbstractPreferenceController(Context context) {
+ public AbstractPreferenceController(@NonNull Context context) {
mContext = context;
mDevicePolicyManager =
(DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt b/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt
index 9aaefe47fda2..58c7907f77de 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt
@@ -37,8 +37,9 @@ class FakeZenModeRepository : ZenModeRepository {
override val globalZenMode: StateFlow<Int>
get() = mutableZenMode.asStateFlow()
- private val mutableModesFlow: MutableStateFlow<List<ZenMode>> =
+ private val mutableModesFlow: MutableStateFlow<List<ZenMode>> by lazy {
MutableStateFlow(listOf(TestModeBuilder.MANUAL_DND))
+ }
override val modes: Flow<List<ZenMode>>
get() = mutableModesFlow.asStateFlow()
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt
index 4c4ce2a61851..01bf0c8335d1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt
@@ -27,6 +27,7 @@ import android.provider.Settings
import androidx.annotation.IntRange
import com.android.internal.util.ConcurrentUtils
import com.android.settingslib.bluetooth.BluetoothUtils
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.settingslib.bluetooth.onBroadcastStartedOrStopped
import com.android.settingslib.bluetooth.onProfileConnectionStateChanged
@@ -71,6 +72,12 @@ interface AudioSharingRepository {
/** The secondary headset groupId in audio sharing. */
val secondaryGroupId: StateFlow<Int>
+ /** Primary audio sharing device. */
+ val primaryDevice: StateFlow<CachedBluetoothDevice?>
+
+ /** Secondary audio sharing device. */
+ val secondaryDevice: StateFlow<CachedBluetoothDevice?>
+
/** The headset groupId to volume map during audio sharing. */
val volumeMap: StateFlow<GroupIdToVolumes>
@@ -144,12 +151,31 @@ class AudioSharingRepositoryImpl(
)
override val secondaryGroupId: StateFlow<Int> =
- merge(
+ secondaryDevice
+ .map { BluetoothUtils.getGroupId(it) }
+ .onEach { logger.onSecondaryGroupIdChanged(it) }
+ .flowOn(backgroundCoroutineContext)
+ .stateIn(
+ coroutineScope,
+ SharingStarted.WhileSubscribed(),
+ BluetoothCsipSetCoordinator.GROUP_ID_INVALID
+ )
+
+ override val primaryDevice: StateFlow<CachedBluetoothDevice?>
+ get() = primaryGroupId.map { getCachedDeviceFromGroupId(it) }
+ .stateIn(
+ coroutineScope,
+ SharingStarted.WhileSubscribed(),
+ null
+ )
+
+ override val secondaryDevice: StateFlow<CachedBluetoothDevice?>
+ get() = merge(
isAudioSharingProfilesReady.flatMapLatest { ready ->
if (ready) {
btManager.profileManager.leAudioBroadcastAssistantProfile
.onSourceConnectedOrRemoved
- .map { getSecondaryGroupId() }
+ .map { getSecondaryDevice() }
} else {
emptyFlow()
}
@@ -160,15 +186,14 @@ class AudioSharingRepositoryImpl(
profileConnection.bluetoothProfile ==
BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT
}
- .map { getSecondaryGroupId() },
- primaryGroupId.map { getSecondaryGroupId() })
- .onStart { emit(getSecondaryGroupId()) }
- .onEach { logger.onSecondaryGroupIdChanged(it) }
+ .map { getSecondaryDevice() },
+ primaryGroupId.map { getSecondaryDevice() })
+ .onStart { emit(getSecondaryDevice()) }
.flowOn(backgroundCoroutineContext)
.stateIn(
coroutineScope,
SharingStarted.WhileSubscribed(),
- BluetoothCsipSetCoordinator.GROUP_ID_INVALID
+ null
)
override val volumeMap: StateFlow<GroupIdToVolumes> =
@@ -257,10 +282,24 @@ class AudioSharingRepositoryImpl(
private fun isBroadcasting(): Boolean =
btManager.profileManager.leAudioBroadcastProfile?.isEnabled(null) ?: false
- private fun getSecondaryGroupId(): Int =
- BluetoothUtils.getGroupId(
- BluetoothUtils.getSecondaryDeviceForBroadcast(contentResolver, btManager)
- )
+ private fun getSecondaryDevice(): CachedBluetoothDevice? =
+ BluetoothUtils.getSecondaryDeviceForBroadcast(contentResolver, btManager)
+
+ private suspend fun getCachedDeviceFromGroupId(groupId: Int): CachedBluetoothDevice? =
+ withContext(backgroundCoroutineContext) {
+ btManager
+ .profileManager
+ ?.leAudioBroadcastAssistantProfile
+ ?.allConnectedDevices
+ ?.firstNotNullOfOrNull { device ->
+ val cachedDevice = btManager.cachedDeviceManager.findDevice(device)
+ if (BluetoothUtils.getGroupId(cachedDevice) == groupId) {
+ cachedDevice
+ } else {
+ null
+ }
+ }
+ }
}
class AudioSharingRepositoryEmptyImpl : AudioSharingRepository {
@@ -269,6 +308,10 @@ class AudioSharingRepositoryEmptyImpl : AudioSharingRepository {
MutableStateFlow(BluetoothCsipSetCoordinator.GROUP_ID_INVALID)
override val secondaryGroupId: StateFlow<Int> =
MutableStateFlow(BluetoothCsipSetCoordinator.GROUP_ID_INVALID)
+ override val primaryDevice: StateFlow<CachedBluetoothDevice?>
+ get() = MutableStateFlow(null)
+ override val secondaryDevice: StateFlow<CachedBluetoothDevice?>
+ get() = MutableStateFlow(null)
override val volumeMap: StateFlow<GroupIdToVolumes> = MutableStateFlow(emptyMap())
override suspend fun audioSharingAvailable(): Boolean = false
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioSharingRepositoryTest.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioSharingRepositoryTest.kt
index 8c5a0851cc92..0f25ae208a69 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioSharingRepositoryTest.kt
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioSharingRepositoryTest.kt
@@ -209,6 +209,21 @@ class AudioSharingRepositoryTest {
}
@Test
+ fun primaryDeviceChange_emitValues() {
+ testScope.runTest {
+ `when`(assistant.allConnectedDevices).thenReturn(listOf(device1, device2))
+
+ val devices = mutableListOf<CachedBluetoothDevice?>()
+ underTest.primaryDevice.onEach { devices.add(it) }.launchIn(backgroundScope)
+ runCurrent()
+ triggerContentObserverChange()
+ runCurrent()
+
+ Truth.assertThat(devices).containsExactly(null, cachedDevice2)
+ }
+ }
+
+ @Test
fun secondaryGroupIdChange_profileNotReady_assistantCallbackNotRegistered() {
testScope.runTest {
val groupIds = mutableListOf<Int?>()
@@ -269,6 +284,29 @@ class AudioSharingRepositoryTest {
}
@Test
+ fun secondaryDeviceChange_emitValues() {
+ testScope.runTest {
+ `when`(broadcast.isProfileReady).thenReturn(true)
+ `when`(assistant.isProfileReady).thenReturn(true)
+ `when`(volumeControl.isProfileReady).thenReturn(true)
+ val devices = mutableListOf<CachedBluetoothDevice?>()
+ underTest.secondaryDevice.onEach { devices.add(it) }.launchIn(backgroundScope)
+ runCurrent()
+ triggerSourceAdded()
+ runCurrent()
+ triggerContentObserverChange()
+ runCurrent()
+
+ Truth.assertThat(devices)
+ .containsExactly(
+ null,
+ cachedDevice2,
+ cachedDevice1,
+ )
+ }
+ }
+
+ @Test
fun volumeMapChange_profileReady_emitValues() {
testScope.runTest {
`when`(broadcast.isProfileReady).thenReturn(true)
@@ -363,7 +401,7 @@ class AudioSharingRepositoryTest {
TEST_GROUP_ID1
)
`when`(assistant.allConnectedDevices).thenReturn(listOf(device1, device2))
- assistantCallbackCaptor.value.sourceAdded(device1, receiveState)
+ assistantCallbackCaptor.value.sourceAdded(device1)
}
private fun triggerSourceRemoved() {
@@ -432,11 +470,9 @@ class AudioSharingRepositoryTest {
onBroadcastStopped(TEST_REASON, TEST_BROADCAST_ID)
}
val sourceAdded:
- BluetoothLeBroadcastAssistant.Callback.(
- sink: BluetoothDevice, state: BluetoothLeBroadcastReceiveState
- ) -> Unit =
- { sink, state ->
- onReceiveStateChanged(sink, TEST_SOURCE_ID, state)
+ BluetoothLeBroadcastAssistant.Callback.(sink: BluetoothDevice) -> Unit =
+ { sink ->
+ onSourceAdded(sink, TEST_SOURCE_ID, TEST_REASON)
}
val sourceRemoved: BluetoothLeBroadcastAssistant.Callback.(sink: BluetoothDevice) -> Unit =
{ sink ->
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
index 3f3e1b280850..c8738ae0c8eb 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
@@ -251,8 +251,8 @@ public class IllustrationPreferenceTest {
mPreference.setMaxHeight(maxHeight);
mPreference.onBindViewHolder(mViewHolder);
- assertThat(mBackgroundView.getMaxHeight()).isEqualTo(restrictedHeight);
- assertThat(mAnimationView.getMaxHeight()).isEqualTo(restrictedHeight);
+ assertThat(mBackgroundView.getMaxHeight()).isEqualTo(maxHeight);
+ assertThat(mAnimationView.getMaxHeight()).isEqualTo(maxHeight);
}
@Test
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index b0309a8fa5a5..6681c014f2e0 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -454,5 +454,6 @@ public class SecureSettingsValidators {
VALIDATORS.put(Secure.MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED,
new InclusiveIntegerRangeValidator(0, 1));
VALIDATORS.put(Secure.ADVANCED_PROTECTION_MODE, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.DISABLE_ADAPTIVE_AUTH_LIMIT_LOCK, BOOLEAN_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index cb656bdd5d54..c47bf628002d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -385,6 +385,9 @@ public class SettingsProvider extends ContentProvider {
private static final Set<String> sDeviceConfigAllowlistedNamespaces = new ArraySet<>();
+ // TODO(b/388901162): Remove this when the same constant is exposed as an API in DeviceConfig.
+ private static final String DEVICE_CONFIG_OVERRIDES_NAMESPACE = "device_config_overrides";
+
// We have to call in the user manager with no lock held,
private volatile UserManager mUserManager;
@@ -1869,7 +1872,7 @@ public class SettingsProvider extends ContentProvider {
}
case MUTATION_OPERATION_RESET -> {
return mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_SECURE,
- UserHandle.USER_SYSTEM, callingPackage, mode, tag);
+ owningUserId, callingPackage, mode, tag);
}
}
}
@@ -2480,12 +2483,21 @@ public class SettingsProvider extends ContentProvider {
for (String flag : flags) {
boolean namespaceAllowed = false;
if (isRestrictedShell) {
- int delimiterIndex = flag.indexOf("/");
- String flagNamespace;
- if (delimiterIndex != -1) {
- flagNamespace = flag.substring(0, delimiterIndex);
- } else {
- flagNamespace = flag;
+ String flagNamespace = getFlagNamespace(flag);
+ // If the namespace indicates this is a flag override, then the actual
+ // namespace and flag name should be used for the allowlist verification.
+ if (DEVICE_CONFIG_OVERRIDES_NAMESPACE.equals(flagNamespace)) {
+ // Override flags are in the following form:
+ // device_config_overrides/namespace:flagName
+ int slashIndex = flag.indexOf("/");
+ int colonIndex = flag.indexOf(":", slashIndex);
+ if (slashIndex != -1 && colonIndex != -1 && (slashIndex + 1) < flag.length()
+ && (colonIndex + 1) < flag.length()) {
+ flagNamespace = flag.substring(slashIndex + 1, colonIndex);
+ StringBuilder flagBuilder = new StringBuilder(flagNamespace);
+ flagBuilder.append("/").append(flag.substring(colonIndex + 1));
+ flag = flagBuilder.toString();
+ }
}
if (allowlistedDeviceConfigNamespaces.contains(flagNamespace)) {
namespaceAllowed = true;
@@ -2512,6 +2524,23 @@ public class SettingsProvider extends ContentProvider {
}
}
+ /**
+ * Returns the namespace for the provided {@code flag}.
+ * <p>
+ * Flags are expected to be in the form namespace/flagName; if the '/' delimiter does
+ * not exist, then the provided flag is returned as the namespace.
+ */
+ private static String getFlagNamespace(String flag) {
+ int delimiterIndex = flag.indexOf("/");
+ String flagNamespace;
+ if (delimiterIndex != -1) {
+ flagNamespace = flag.substring(0, delimiterIndex);
+ } else {
+ flagNamespace = flag;
+ }
+ return flagNamespace;
+ }
+
// The check is added mainly for auto devices. On auto devices, it is possible that
// multiple users are visible simultaneously using visible background users.
// In such cases, it is desired that Non-current user (ex. visible background users) can
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index bf3afeda448e..0f6311552de9 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -408,77 +408,8 @@ public class SettingsState {
Slog.w(LOG_TAG, "Bulk sync request to acongid failed.");
}
}
-
- if (Flags.disableBulkCompare()) {
- return;
- }
-
- // TOBO(b/312444587): remove the comparison logic after Test Mission 2.
- if (requests == null) {
- Map<String, AconfigdFlagInfo> aconfigdFlagMap =
- AconfigdJavaUtils.listFlagsValueInNewStorage(localSocket);
- compareFlagValueInNewStorage(
- mAconfigDefaultFlags,
- aconfigdFlagMap);
- }
- }
- }
- }
-
- // TODO(b/312444587): remove the comparison logic after Test Mission 2.
- public int compareFlagValueInNewStorage(
- Map<String, AconfigdFlagInfo> defaultFlagMap,
- Map<String, AconfigdFlagInfo> aconfigdFlagMap) {
-
- // Get all defaults from the default map. The mSettings may not contain
- // all flags, since it only contains updated flags.
- int diffNum = 0;
- for (Map.Entry<String, AconfigdFlagInfo> entry : defaultFlagMap.entrySet()) {
- String key = entry.getKey();
- AconfigdFlagInfo flag = entry.getValue();
-
- AconfigdFlagInfo aconfigdFlag = aconfigdFlagMap.get(key);
- if (aconfigdFlag == null) {
- Slog.w(LOG_TAG, String.format("Flag %s is missing from aconfigd", key));
- diffNum++;
- continue;
- }
- String diff = flag.dumpDiff(aconfigdFlag);
- if (!diff.isEmpty()) {
- Slog.w(
- LOG_TAG,
- String.format(
- "Flag %s is different in Settings and aconfig: %s", key, diff));
- diffNum++;
- }
- }
-
- for (String key : aconfigdFlagMap.keySet()) {
- if (defaultFlagMap.containsKey(key)) continue;
- Slog.w(LOG_TAG, String.format("Flag %s is missing from Settings", key));
- diffNum++;
- }
-
- String compareMarkerName = "aconfigd_marker/compare_diff_num";
- synchronized (mLock) {
- Setting markerSetting = mSettings.get(compareMarkerName);
- if (markerSetting == null) {
- markerSetting =
- new Setting(
- compareMarkerName,
- String.valueOf(diffNum),
- false,
- "aconfig",
- "aconfig");
- mSettings.put(compareMarkerName, markerSetting);
}
- markerSetting.value = String.valueOf(diffNum);
- }
-
- if (diffNum == 0) {
- Slog.w(LOG_TAG, "Settings and new storage have same flags.");
}
- return diffNum;
}
@GuardedBy("mLock")
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig b/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig
index cfd27c69032e..4fc3b873aa75 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig
+++ b/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig
@@ -100,14 +100,4 @@ flag {
metadata {
purpose: PURPOSE_BUGFIX
}
-}
-
-flag {
- name: "disable_bulk_compare"
- namespace: "core_experiments_team_internal"
- description: "Disable bulk comparison between DeviceConfig and aconfig storage."
- bug: "312444587"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
} \ No newline at end of file
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index cbdb36fff98c..9aad5d5f8367 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -689,6 +689,7 @@ public class SettingsBackupTest {
Settings.Secure.DEFAULT_DEVICE_INPUT_METHOD,
Settings.Secure.DEVICE_PAIRED,
Settings.Secure.DIALER_DEFAULT_APPLICATION,
+ Settings.Secure.DISABLE_ADAPTIVE_AUTH_LIMIT_LOCK,
Settings.Secure.DISABLED_PRINT_SERVICES,
Settings.Secure.DISABLE_SECURE_WINDOWS,
Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS,
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index 276b206cd6a1..6e7576631147 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -1303,85 +1303,4 @@ public class SettingsStateTest {
assertFalse(flag3.getHasServerOverride());
assertFalse(flag3.getHasLocalOverride());
}
-
- @Test
- @RequiresFlagsDisabled(Flags.FLAG_DISABLE_BULK_COMPARE)
- public void testCompareFlagValueInNewStorage() {
- int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0);
- Object lock = new Object();
- SettingsState settingsState =
- new SettingsState(
- InstrumentationRegistry.getContext(),
- lock,
- mSettingsFile,
- configKey,
- SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED,
- Looper.getMainLooper());
-
- AconfigdFlagInfo defaultFlag1 =
- AconfigdFlagInfo.newBuilder()
- .setPackageName("com.android.flags")
- .setFlagName("flag1")
- .setDefaultFlagValue("false")
- .setServerFlagValue("true")
- .setHasServerOverride(true)
- .setIsReadWrite(true)
- .build();
-
- AconfigdFlagInfo expectedFlag1 =
- AconfigdFlagInfo.newBuilder()
- .setPackageName("com.android.flags")
- .setFlagName("flag1")
- .setServerFlagValue("true")
- .setDefaultFlagValue("false")
- .setHasServerOverride(true)
- .setIsReadWrite(true)
- .build();
-
- Map<String, AconfigdFlagInfo> aconfigdMap = new HashMap<>();
- Map<String, AconfigdFlagInfo> defaultMap = new HashMap<>();
-
- defaultMap.put("com.android.flags.flag1", defaultFlag1);
- aconfigdMap.put("com.android.flags.flag1", expectedFlag1);
-
- int ret = settingsState.compareFlagValueInNewStorage(defaultMap, aconfigdMap);
- assertEquals(0, ret);
-
- String value =
- settingsState.getSettingLocked("aconfigd_marker/compare_diff_num").getValue();
- assertEquals("0", value);
-
- AconfigdFlagInfo defaultFlag2 =
- AconfigdFlagInfo.newBuilder()
- .setPackageName("com.android.flags")
- .setFlagName("flag2")
- .setDefaultFlagValue("false")
- .build();
- defaultMap.put("com.android.flags.flag2", defaultFlag2);
-
- ret = settingsState.compareFlagValueInNewStorage(defaultMap, aconfigdMap);
- // missing from new storage
- assertEquals(1, ret);
- value =
- settingsState.getSettingLocked("aconfigd_marker/compare_diff_num").getValue();
- assertEquals("1", value);
-
- AconfigdFlagInfo expectedFlag2 =
- AconfigdFlagInfo.newBuilder()
- .setPackageName("com.android.flags")
- .setFlagName("flag2")
- .setServerFlagValue("true")
- .setLocalFlagValue("true")
- .setDefaultFlagValue("false")
- .setHasServerOverride(true)
- .setHasLocalOverride(true)
- .build();
- aconfigdMap.put("com.android.flags.flag2", expectedFlag2);
- ret = settingsState.compareFlagValueInNewStorage(defaultMap, aconfigdMap);
- // skip the server and local value comparison when the flag is read_only
- assertEquals(0, ret);
- value =
- settingsState.getSettingLocked("aconfigd_marker/compare_diff_num").getValue();
- assertEquals("0", value);
- }
}
diff --git a/packages/Shell/res/values-iw/strings.xml b/packages/Shell/res/values-iw/strings.xml
index 816fe3b432bc..be81c2ed3792 100644
--- a/packages/Shell/res/values-iw/strings.xml
+++ b/packages/Shell/res/values-iw/strings.xml
@@ -24,10 +24,10 @@
<string name="bugreport_updating_wait" msgid="3322151947853929470">"רק רגע…"</string>
<string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"הדוח על הבאג יופיע בטלפון בקרוב"</string>
<string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"יש להקיש כדי לשתף את הדוח על הבאג"</string>
- <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"יש להקיש כדי לשתף את הדוח על הבאג"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"יש ללחוץ כדי לשתף את הדוח על הבאג"</string>
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"אפשר להחליק ימינה כדי לשתף את הדוח על הבאג ללא צילום מסך, או להמתין להשלמת צילום המסך"</string>
- <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"יש להקיש כדי לשתף את הדוח על הבאג ללא צילום מסך, או להמתין להשלמת צילום המסך"</string>
- <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"יש להקיש כדי לשתף את הדוח על הבאג ללא צילום מסך, או להמתין להשלמת צילום המסך"</string>
+ <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"יש ללחוץ כדי לשתף את הדוח על הבאג ללא צילום מסך, או להמתין להשלמת צילום המסך"</string>
+ <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"יש ללחוץ כדי לשתף את הדוח על הבאג ללא צילום מסך, או להמתין להשלמת צילום המסך"</string>
<string name="bugreport_confirm" msgid="5917407234515812495">"דוחות על באגים כוללים נתונים מקובצי היומן השונים במערכת, שעשויים לכלול נתונים הנחשבים רגישים (כגון שימוש באפליקציות ונתוני מיקום). כדאי לשתף דוחות על באגים רק עם אפליקציות ואנשים מהימנים."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"אין צורך להציג זאת שוב"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"דוחות על באגים"</string>
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 6b2449fdaa49..a935aacacf95 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -423,6 +423,7 @@ android_library {
],
manifest: "AndroidManifest-res.xml",
flags_packages: [
+ "android.app.flags-aconfig",
"com_android_systemui_flags",
],
}
@@ -519,6 +520,7 @@ android_library {
"androidx.activity_activity-compose",
"androidx.compose.animation_animation-graphics",
"androidx.lifecycle_lifecycle-viewmodel-compose",
+ "kairos",
],
libs: [
"keepanno-annotations",
@@ -739,6 +741,7 @@ android_library {
"PlatformMotionTesting",
"SystemUICustomizationTestUtils",
"androidx.compose.runtime_runtime",
+ "kairos",
"kosmos",
"testables",
"androidx.test.rules",
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 51ea5298fbb8..b53198d8ae98 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -406,7 +406,7 @@
android:killAfterRestore="false"
android:hardwareAccelerated="true"
android:label="@string/app_label"
- android:icon="@drawable/android15_patch_adaptive"
+ android:icon="@drawable/android16_patch_adaptive"
android:process="com.android.systemui"
android:supportsRtl="true"
android:theme="@style/Theme.SystemUI"
@@ -547,6 +547,12 @@
android:permission="android.permission.BIND_WALLPAPER"
android:exported="true" />
+ <service android:name=".wallpapers.GradientColorWallpaper"
+ android:featureFlag="android.app.enable_connected_displays_wallpaper"
+ android:singleUser="true"
+ android:permission="android.permission.BIND_WALLPAPER"
+ android:exported="true" />
+
<activity android:name=".tuner.TunerActivity"
android:enabled="false"
android:icon="@drawable/tuner"
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index c6cc9a975191..07262533b81a 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -24,6 +24,7 @@ bhinegardner@google.com
bhnm@google.com
brycelee@google.com
brzezinski@google.com
+burakov@google.com
caitlinshk@google.com
cameronyee@google.com
chandruis@google.com
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/AndroidManifest.xml b/packages/SystemUI/accessibility/accessibilitymenu/AndroidManifest.xml
index 0f210e7e5e7b..b40a11469172 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/AndroidManifest.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/AndroidManifest.xml
@@ -20,7 +20,10 @@
<uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS"/>
<uses-permission android:name="android.permission.MANAGE_USERS"/>
- <application android:supportsRtl="true">
+ <application
+ android:supportsRtl="true"
+ android:allowBackup="true"
+ android:restoreAnyVersion="true">
<service
android:name="com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService"
android:exported="false"
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-iw/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-iw/strings.xml
index 3f8671c83ccc..db733fc33a21 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-iw/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-iw/strings.xml
@@ -23,8 +23,8 @@
<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_summary" msgid="236873938502785311">"הגדלת הלחצנים של תפריט הנגישות"</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>
<string name="music_volume_percentage_label" msgid="398635599662604706">"עוצמת הקול של המוזיקה %% <xliff:g id="PERCENTAGE">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/aconfig/Android.bp b/packages/SystemUI/aconfig/Android.bp
index 1858c80ca901..088ec136f24e 100644
--- a/packages/SystemUI/aconfig/Android.bp
+++ b/packages/SystemUI/aconfig/Android.bp
@@ -23,6 +23,7 @@ package {
default_team: "trendy_team_system_ui_please_use_a_more_specific_subteam_if_possible_",
default_visibility: [
"//visibility:override",
+ "//frameworks/base/libs/WindowManager/Shell:__subpackages__",
"//frameworks/base/packages/SystemUI:__subpackages__",
"//frameworks/libs/systemui/tracinglib:__subpackages__",
"//frameworks/base/services/accessibility:__subpackages__",
diff --git a/packages/SystemUI/aconfig/accessibility.aconfig b/packages/SystemUI/aconfig/accessibility.aconfig
index b5eba08c8f87..fb21be4c3bd1 100644
--- a/packages/SystemUI/aconfig/accessibility.aconfig
+++ b/packages/SystemUI/aconfig/accessibility.aconfig
@@ -38,6 +38,16 @@ flag {
}
flag {
+ name: "floating_menu_display_cutout_support"
+ namespace: "accessibility"
+ description: "Makes FAB properly react to and avoid DisplayCutouts."
+ bug: "384399408"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "floating_menu_drag_to_hide"
namespace: "accessibility"
description: "Allows users to hide the FAB then use notification to dismiss or bring it back."
@@ -125,3 +135,13 @@ flag {
description: "Update hearing device icon in floating menu according to the connection status."
bug: "357882387"
}
+
+flag {
+ name: "floating_menu_notify_targets_changed_on_strict_diff"
+ namespace: "accessibility"
+ description: "Only notify listeners that the list of accessibility targets has changed if the lists are not identical."
+ bug: "376473165"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index a0d7fd28f5f8..9531bc38e797 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -382,6 +382,13 @@ flag {
}
flag {
+ name: "status_bar_mobile_icon_kairos"
+ namespace: "systemui"
+ description: "Refactors the mobile connection icon in the status bar to use the Kairos library"
+ bug: "383172066"
+}
+
+flag {
name: "status_bar_monochrome_icons_fix"
namespace: "systemui"
description: "Fixes the status bar icon size when drawing InsetDrawables (ie. monochrome icons)"
@@ -486,6 +493,14 @@ flag {
}
flag {
+ name: "status_bar_no_hun_behavior"
+ namespace: "systemui"
+ description: "When there's a HUN, don't show the HUN text or icon in the status bar. Instead, "
+ "continue showing the usual status bar."
+ bug: "385740230"
+}
+
+flag {
name: "promote_notifications_automatically"
namespace: "systemui"
description: "Flag to automatically turn certain notifications into promoted notifications so "
@@ -610,13 +625,6 @@ flag {
}
flag {
- name: "status_bar_connected_displays"
- namespace: "lse_desktop_experience"
- description: "Shows the status bar on connected displays"
- bug: "379264862"
-}
-
-flag {
name: "status_bar_switch_to_spn_from_data_spn"
namespace: "systemui"
description: "Fix usage of the SPN broadcast extras"
@@ -1507,16 +1515,6 @@ flag {
}
flag {
- name: "sim_pin_talkback_fix_for_double_submit"
- namespace: "systemui"
- description: "The SIM PIN entry screens show the wrong message due"
- bug: "346932439"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "sim_pin_bouncer_reset"
namespace: "systemui"
description: "The SIM PIN bouncer does not close after unlocking"
@@ -1912,3 +1910,33 @@ flag {
description: "Special UI treatment for magic actions"
bug: "383567383"
}
+
+flag {
+ name: "show_audio_sharing_slider_in_volume_panel"
+ namespace: "cross_device_experiences"
+ description: "Show two sliders in volume panel when audio sharing."
+ bug: "336183611"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "stabilize_heads_up_group"
+ namespace: "systemui"
+ description: "Stabilize heads up groups in VisualStabilityCoordinator"
+ bug: "381864715"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "magnetic_notification_horizontal_swipe"
+ namespace: "systemui"
+ description: "Add support for magnetic behavior on horizontal notification swipes."
+ bug: "390179908"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java
index 2e8f92839fa6..4b8610884b05 100644
--- a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java
+++ b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java
@@ -185,16 +185,24 @@ public class ViewUIComponent implements UIComponent {
return;
}
ViewGroup.LayoutParams params = mView.getLayoutParams();
- if (params == null || params.width == 0 || params.height == 0) {
+ if (params == null) {
// layout pass didn't happen.
logD("draw: skipped - no layout");
return;
}
+
+ final Rect realBounds = getRealBounds();
+ if (realBounds.width() == 0 || realBounds.height() == 0) {
+ // bad bounds.
+ logD("draw: skipped - zero bounds");
+ return;
+ }
+
+
Canvas canvas = mSurface.lockHardwareCanvas();
// Clear the canvas first.
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
if (mVisibleOverride) {
- Rect realBounds = getRealBounds();
Rect renderBounds = getBounds();
canvas.translate(renderBounds.left, renderBounds.top);
canvas.scale(
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java
index 8a57e8cbbb20..f36f0306d82b 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java
@@ -27,6 +27,7 @@ import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_EXIT_TRAN
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static com.android.internal.util.Preconditions.checkArgument;
+import static com.android.wm.shell.shared.TransitionUtil.FLAG_IS_DESKTOP_WALLPAPER_ACTIVITY;
import static com.android.wm.shell.shared.TransitionUtil.isClosingMode;
import static com.android.wm.shell.shared.TransitionUtil.isClosingType;
import static com.android.wm.shell.shared.TransitionUtil.isOpeningMode;
@@ -270,7 +271,8 @@ public abstract class RemoteAnimationRunnerCompat extends IRemoteAnimationRunner
// skip changes that we didn't wrap
if (!leashMap.containsKey(change.getLeash())) continue;
// Only make the update if we are closing Desktop tasks.
- if (change.getTaskInfo() != null && change.getTaskInfo().isFreeform()
+ if (change.getTaskInfo() != null && (change.getTaskInfo().isFreeform()
+ || change.hasFlags(FLAG_IS_DESKTOP_WALLPAPER_ACTIVITY))
&& isClosingMode(change.getMode())) {
startTransaction.setAlpha(leashMap.get(launcherChange.getLeash()), 0f);
return;
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/ui/graphics/DrawInContainer.kt b/packages/SystemUI/compose/core/src/com/android/compose/ui/graphics/DrawInContainer.kt
index 311519122312..d08d859ec0d7 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/ui/graphics/DrawInContainer.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/ui/graphics/DrawInContainer.kt
@@ -19,9 +19,11 @@ package com.android.compose.ui.graphics
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithContent
+import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
import androidx.compose.ui.graphics.drawscope.DrawScope
@@ -30,14 +32,14 @@ import androidx.compose.ui.graphics.drawscope.translate
import androidx.compose.ui.graphics.layer.GraphicsLayer
import androidx.compose.ui.graphics.layer.drawLayer
import androidx.compose.ui.layout.LayoutCoordinates
-import androidx.compose.ui.layout.layout
+import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.layout.positionInWindow
import androidx.compose.ui.modifier.ModifierLocalModifierNode
import androidx.compose.ui.node.DrawModifierNode
+import androidx.compose.ui.node.LayoutAwareModifierNode
import androidx.compose.ui.node.ModifierNodeElement
import androidx.compose.ui.node.requireDensity
import androidx.compose.ui.node.requireGraphicsContext
-import androidx.compose.ui.node.requireLayoutCoordinates
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.util.fastForEach
@@ -48,17 +50,7 @@ import androidx.compose.ui.util.fastForEach
* The elements redirected to this container will be drawn above the content of this composable.
*/
fun Modifier.container(state: ContainerState): Modifier {
- return layout { measurable, constraints ->
- val p = measurable.measure(constraints)
- layout(p.width, p.height) {
- val coords = coordinates
- if (coords != null && !isLookingAhead) {
- state.lastCoords = coords
- }
-
- p.place(0, 0)
- }
- }
+ return onPlaced { state.lastOffsetInWindow = it.positionInWindow() }
.drawWithContent {
drawContent()
state.drawInOverlay(this)
@@ -91,7 +83,7 @@ fun Modifier.drawInContainer(
class ContainerState {
private var renderers = mutableStateListOf<LayerRenderer>()
- internal var lastCoords: LayoutCoordinates? = null
+ internal var lastOffsetInWindow by mutableStateOf(Offset.Zero)
internal fun onLayerRendererAttached(renderer: LayerRenderer) {
renderers.add(renderer)
@@ -142,7 +134,8 @@ internal class DrawInContainerNode(
var enabled: () -> Boolean = { true },
zIndex: Float = 0f,
var clipPath: (LayoutDirection, Density) -> Path? = { _, _ -> null },
-) : Modifier.Node(), DrawModifierNode, ModifierLocalModifierNode {
+) : Modifier.Node(), LayoutAwareModifierNode, DrawModifierNode, ModifierLocalModifierNode {
+ private var lastOffsetInWindow by mutableStateOf(Offset.Zero)
var zIndex by mutableFloatStateOf(zIndex)
private inner class LayerWithRenderer(val layer: GraphicsLayer) : LayerRenderer {
@@ -152,11 +145,7 @@ internal class DrawInContainerNode(
override fun drawInOverlay(drawScope: DrawScope) {
if (enabled()) {
with(drawScope) {
- val containerCoords =
- checkNotNull(state.lastCoords) { "container is not placed" }
- val (x, y) =
- requireLayoutCoordinates().positionInWindow() -
- containerCoords.positionInWindow()
+ val (x, y) = lastOffsetInWindow - state.lastOffsetInWindow
val clipPath = clipPath(layoutDirection, requireDensity())
if (clipPath != null) {
clipPath(clipPath) { translate(x, y) { drawLayer(layer) } }
@@ -178,6 +167,10 @@ internal class DrawInContainerNode(
}
}
+ override fun onPlaced(coordinates: LayoutCoordinates) {
+ lastOffsetInWindow = coordinates.positionInWindow()
+ }
+
val layer: GraphicsLayer?
get() = layerWithRenderer?.layer
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 0054a4c899ec..d43b596b32f1 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
@@ -87,10 +87,10 @@ import androidx.compose.ui.unit.times
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.PlatformButton
import com.android.compose.animation.Easings
+import com.android.compose.animation.scene.ContentScope
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
import com.android.compose.animation.scene.transitions
import com.android.compose.windowsizeclass.LocalWindowSizeClass
@@ -168,7 +168,7 @@ private fun StandardLayout(viewModel: BouncerSceneContentViewModel, modifier: Mo
LocalWindowSizeClass.current.heightSizeClass == WindowHeightSizeClass.Expanded
FoldAware(
- modifier = modifier.padding(start = 32.dp, top = 92.dp, end = 32.dp, bottom = 48.dp),
+ modifier = modifier.padding(top = 92.dp, bottom = 48.dp),
viewModel = viewModel,
aboveFold = {
Column(
@@ -515,7 +515,7 @@ private fun FoldAware(
}
@Composable
-private fun SceneScope.FoldableScene(
+private fun ContentScope.FoldableScene(
aboveFold: @Composable BoxScope.() -> Unit,
belowFold: @Composable BoxScope.() -> Unit,
isSplit: Boolean,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
index 55b42931b1fa..fad8ae7e3ba2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
@@ -24,8 +24,8 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.Modifier
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.bouncer.ui.BouncerDialogFactory
@@ -73,7 +73,7 @@ constructor(
}
@Composable
- override fun SceneScope.Content(modifier: Modifier) =
+ override fun ContentScope.Content(modifier: Modifier) =
BouncerScene(
viewModel = rememberViewModel("BouncerScene") { contentViewModelFactory.create() },
dialogFactory = dialogFactory,
@@ -82,7 +82,7 @@ constructor(
}
@Composable
-private fun SceneScope.BouncerScene(
+private fun ContentScope.BouncerScene(
viewModel: BouncerSceneContentViewModel,
dialogFactory: BouncerDialogFactory,
modifier: Modifier = Modifier,
@@ -96,8 +96,8 @@ private fun SceneScope.BouncerScene(
drawRect(color = backgroundColor)
}
- // Separate the bouncer content into a reusable composable that doesn't have any SceneScope
- // dependencies
+ // Separate the bouncer content into a reusable composable that doesn't have any
+ // ContentScope dependencies
BouncerContent(
viewModel,
dialogFactory,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
index 8321238b28b1..3d0354a578f7 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
@@ -24,6 +24,8 @@ import androidx.compose.foundation.Canvas
import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.detectDragGestures
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.material3.MaterialTheme
@@ -35,6 +37,7 @@ 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
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.geometry.Offset
@@ -45,6 +48,7 @@ import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.integerResource
+import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.Easings
@@ -212,23 +216,27 @@ fun PatternBouncer(
var gridCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
var offset: Offset by remember { mutableStateOf(Offset.Zero) }
var scale: Float by remember { mutableStateOf(1f) }
+ // This is the size of the drawing area, in dips.
+ val dotDrawingArea =
+ remember(colCount, rowCount) {
+ DpSize(
+ // Because the width also includes spacing to the left and right of the leftmost and
+ // rightmost dots in the grid and because UX mocks specify the width without that
+ // spacing, the actual width needs to be defined slightly bigger than the UX mock
+ // width.
+ width = (262 * colCount / 2).dp,
+ // Because the height also includes spacing above and below the topmost and
+ // bottommost
+ // dots in the grid and because UX mocks specify the height without that spacing,
+ // the
+ // actual height needs to be defined slightly bigger than the UX mock height.
+ height = (262 * rowCount / 2).dp,
+ )
+ }
- Canvas(
- modifier
- .sysuiResTag("bouncer_pattern_root")
- // Because the width also includes spacing to the left and right of the leftmost and
- // rightmost dots in the grid and because UX mocks specify the width without that
- // spacing, the actual width needs to be defined slightly bigger than the UX mock width.
- .width((262 * colCount / 2).dp)
- // Because the height also includes spacing above and below the topmost and bottommost
- // dots in the grid and because UX mocks specify the height without that spacing, the
- // actual height needs to be defined slightly bigger than the UX mock height.
- .height((262 * rowCount / 2).dp)
- // Need to clip to bounds to make sure that the lines don't follow the input pointer
- // when it leaves the bounds of the dot grid.
- .clipToBounds()
- .onGloballyPositioned { coordinates -> gridCoordinates = coordinates }
- .thenIf(isInputEnabled) {
+ Box(
+ modifier =
+ modifier.fillMaxWidth().thenIf(isInputEnabled) {
Modifier.pointerInput(Unit) {
awaitEachGesture {
awaitFirstDown()
@@ -257,105 +265,125 @@ fun PatternBouncer(
inputPosition = change.position
change.position.minus(offset).div(scale).let {
viewModel.onDrag(
- xPx = it.x,
+ xPx =
+ it.x -
+ ((size.width - dotDrawingArea.width.roundToPx()) / 2),
yPx = it.y,
- containerSizePx = size.width,
+ containerSizePx = dotDrawingArea.width.roundToPx(),
)
}
}
}
}
- .motionTestValues {
- entryAnimationCompleted exportAs entryCompleted
- dotAppearFadeInAnimatables.map { it.value.value } exportAs dotAppearFadeIn
- dotAppearMoveUpAnimatables.map { it.value.value } exportAs dotAppearMoveUp
- dotScalingAnimatables.map { it.value.value } exportAs dotScaling
- }
) {
- gridCoordinates?.let { nonNullCoordinates ->
- val containerSize = nonNullCoordinates.size
- if (containerSize.width <= 0 || containerSize.height <= 0) {
- return@let
- }
+ Canvas(
+ Modifier.sysuiResTag("bouncer_pattern_root")
+ .width(dotDrawingArea.width)
+ .height(dotDrawingArea.height)
+ // Need to clip to bounds to make sure that the lines don't follow the input pointer
+ // when it leaves the bounds of the dot grid.
+ .clipToBounds()
+ .align(Alignment.Center)
+ .onGloballyPositioned { coordinates -> gridCoordinates = coordinates }
+ .motionTestValues {
+ entryAnimationCompleted exportAs entryCompleted
+ dotAppearFadeInAnimatables.map { it.value.value } exportAs dotAppearFadeIn
+ dotAppearMoveUpAnimatables.map { it.value.value } exportAs dotAppearMoveUp
+ dotScalingAnimatables.map { it.value.value } exportAs dotScaling
+ }
+ ) {
+ gridCoordinates?.let { nonNullCoordinates ->
+ val containerSize = nonNullCoordinates.size
+ if (containerSize.width <= 0 || containerSize.height <= 0) {
+ return@let
+ }
- val horizontalSpacing = containerSize.width.toFloat() / colCount
- val verticalSpacing = containerSize.height.toFloat() / rowCount
- val spacing = min(horizontalSpacing, verticalSpacing)
- val horizontalOffset =
- offset(
- availableSize = containerSize.width,
- spacingPerDot = spacing,
- dotCount = colCount,
- isCentered = true,
- )
- val verticalOffset =
- offset(
- availableSize = containerSize.height,
- spacingPerDot = spacing,
- dotCount = rowCount,
- isCentered = centerDotsVertically,
- )
- offset = Offset(horizontalOffset, verticalOffset)
- scale = (colCount * spacing) / containerSize.width
+ val horizontalSpacing = containerSize.width.toFloat() / colCount
+ val verticalSpacing = containerSize.height.toFloat() / rowCount
+ val spacing = min(horizontalSpacing, verticalSpacing)
+ val horizontalOffset =
+ offset(
+ availableSize = containerSize.width,
+ spacingPerDot = spacing,
+ dotCount = colCount,
+ isCentered = true,
+ )
+ val verticalOffset =
+ offset(
+ availableSize = containerSize.height,
+ spacingPerDot = spacing,
+ dotCount = rowCount,
+ isCentered = centerDotsVertically,
+ )
+ offset = Offset(horizontalOffset, verticalOffset)
+ scale = (colCount * spacing) / containerSize.width
- if (isAnimationEnabled) {
- // Draw lines between dots.
- selectedDots.forEachIndexed { index, dot ->
- if (index > 0) {
- val previousDot = selectedDots[index - 1]
- val lineFadeOutAnimationProgress =
- lineFadeOutAnimatables[previousDot]!!.value
- val startLerp = 1 - lineFadeOutAnimationProgress
- val from =
- pixelOffset(previousDot, spacing, horizontalOffset, verticalOffset)
- val to = pixelOffset(dot, spacing, horizontalOffset, verticalOffset)
- val lerpedFrom =
- Offset(
- x = from.x + (to.x - from.x) * startLerp,
- y = from.y + (to.y - from.y) * startLerp,
+ if (isAnimationEnabled) {
+ // Draw lines between dots.
+ selectedDots.forEachIndexed { index, dot ->
+ if (index > 0) {
+ val previousDot = selectedDots[index - 1]
+ val lineFadeOutAnimationProgress =
+ lineFadeOutAnimatables[previousDot]!!.value
+ val startLerp = 1 - lineFadeOutAnimationProgress
+ val from =
+ pixelOffset(previousDot, spacing, horizontalOffset, verticalOffset)
+ val to = pixelOffset(dot, spacing, horizontalOffset, verticalOffset)
+ val lerpedFrom =
+ Offset(
+ x = from.x + (to.x - from.x) * startLerp,
+ y = from.y + (to.y - from.y) * startLerp,
+ )
+ drawLine(
+ start = lerpedFrom,
+ end = to,
+ cap = StrokeCap.Round,
+ alpha = lineFadeOutAnimationProgress * lineAlpha(spacing),
+ color = lineColor,
+ strokeWidth = lineStrokeWidth,
)
- drawLine(
- start = lerpedFrom,
- end = to,
- cap = StrokeCap.Round,
- alpha = lineFadeOutAnimationProgress * lineAlpha(spacing),
- color = lineColor,
- strokeWidth = lineStrokeWidth,
- )
+ }
}
- }
- // Draw the line between the most recently-selected dot and the input pointer
- // position.
- inputPosition?.let { lineEnd ->
- currentDot?.let { dot ->
- val from = pixelOffset(dot, spacing, horizontalOffset, verticalOffset)
- val lineLength =
- sqrt((from.y - lineEnd.y).pow(2) + (from.x - lineEnd.x).pow(2))
- drawLine(
- start = from,
- end = lineEnd,
- cap = StrokeCap.Round,
- alpha = lineAlpha(spacing, lineLength),
- color = lineColor,
- strokeWidth = lineStrokeWidth,
- )
+ // Draw the line between the most recently-selected dot and the input pointer
+ // position.
+ inputPosition?.let { lineEnd ->
+ currentDot?.let { dot ->
+ val from = pixelOffset(dot, spacing, horizontalOffset, verticalOffset)
+ val lineLength =
+ sqrt((from.y - lineEnd.y).pow(2) + (from.x - lineEnd.x).pow(2))
+ drawLine(
+ start = from,
+ end = lineEnd,
+ cap = StrokeCap.Round,
+ alpha = lineAlpha(spacing, lineLength),
+ color = lineColor,
+ strokeWidth = lineStrokeWidth,
+ )
+ }
}
}
- }
- // Draw each dot on the grid.
- dots.forEach { dot ->
- val initialOffset = checkNotNull(dotAppearMaxOffsetPixels[dot])
- val appearOffset =
- (1 - checkNotNull(dotAppearMoveUpAnimatables[dot]).value) * initialOffset
- drawCircle(
- center =
- pixelOffset(dot, spacing, horizontalOffset, verticalOffset + appearOffset),
- color =
- dotColor.copy(alpha = checkNotNull(dotAppearFadeInAnimatables[dot]).value),
- radius = dotRadius * checkNotNull(dotScalingAnimatables[dot]).value,
- )
+ // Draw each dot on the grid.
+ dots.forEach { dot ->
+ val initialOffset = checkNotNull(dotAppearMaxOffsetPixels[dot])
+ val appearOffset =
+ (1 - checkNotNull(dotAppearMoveUpAnimatables[dot]).value) * initialOffset
+ drawCircle(
+ center =
+ pixelOffset(
+ dot,
+ spacing,
+ horizontalOffset,
+ verticalOffset + appearOffset,
+ ),
+ color =
+ dotColor.copy(
+ alpha = checkNotNull(dotAppearFadeInAnimatables[dot]).value
+ ),
+ radius = dotRadius * checkNotNull(dotScalingAnimatables[dot]).value,
+ )
+ }
}
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index a2a91fcd5d52..9b5ff7f9e7e8 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -33,13 +33,13 @@ import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ContentKey
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.ElementMatcher
import com.android.compose.animation.scene.LowestZIndexContentPicker
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
import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.observableTransitionState
@@ -229,7 +229,7 @@ fun CommunalContainer(
/** Scene containing the glanceable hub UI. */
@Composable
-fun SceneScope.CommunalScene(
+fun ContentScope.CommunalScene(
backgroundType: CommunalBackgroundType,
colors: CommunalColors,
content: CommunalContent,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
index 0a0003ee9a8a..fea34921b853 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
@@ -31,7 +31,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
import com.android.systemui.communal.smartspace.SmartspaceInteractionHandler
import com.android.systemui.communal.ui.compose.section.AmbientStatusBarSection
@@ -65,7 +65,7 @@ constructor(
) {
@Composable
- fun SceneScope.Content(modifier: Modifier = Modifier) {
+ fun ContentScope.Content(modifier: Modifier = Modifier) {
CommunalTouchableSurface(viewModel = viewModel, modifier = modifier) {
Layout(
modifier = Modifier.fillMaxSize(),
@@ -81,7 +81,7 @@ constructor(
dialogFactory = dialogFactory,
widgetSection = widgetSection,
modifier = Modifier.element(Communal.Elements.Grid),
- sceneScope = this@Content,
+ contentScope = this@Content,
)
}
if (communalSettingsInteractor.isV2FlagEnabled()) {
@@ -193,6 +193,7 @@ constructor(
companion object {
private val screensaverButtonSize: Dp = 64.dp
private val screensaverButtonPadding: Dp = 24.dp
+
// TODO(b/382739998): Remove these hardcoded values once lock icon size and bottom area
// position are sorted.
private val lockIconSize: Dp = 54.dp
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 068df8e31ed0..70a74f064563 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
@@ -171,7 +171,7 @@ import androidx.compose.ui.zIndex
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.window.layout.WindowMetricsCalculator
import com.android.compose.animation.Easings.Emphasized
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.modifiers.thenIf
import com.android.compose.ui.graphics.painter.rememberDrawablePainter
import com.android.internal.R.dimen.system_app_widget_background_radius
@@ -217,7 +217,7 @@ fun CommunalHub(
widgetConfigurator: WidgetConfigurator? = null,
onOpenWidgetPicker: (() -> Unit)? = null,
onEditDone: (() -> Unit)? = null,
- sceneScope: SceneScope? = null,
+ contentScope: ContentScope? = null,
) {
val communalContent by
viewModel.communalContent.collectAsStateWithLifecycle(initialValue = emptyList())
@@ -437,7 +437,7 @@ fun CommunalHub(
widgetConfigurator = widgetConfigurator,
interactionHandler = interactionHandler,
widgetSection = widgetSection,
- sceneScope = sceneScope,
+ contentScope = contentScope,
)
}
}
@@ -827,7 +827,7 @@ private fun BoxScope.CommunalHubLazyGrid(
widgetConfigurator: WidgetConfigurator?,
interactionHandler: RemoteViews.InteractionHandler?,
widgetSection: CommunalAppWidgetSection,
- sceneScope: SceneScope?,
+ contentScope: ContentScope?,
) {
var gridModifier =
Modifier.align(Alignment.TopStart).onGloballyPositioned { setGridCoordinates(it) }
@@ -1009,7 +1009,7 @@ private fun BoxScope.CommunalHubLazyGrid(
interactionHandler = interactionHandler,
widgetSection = widgetSection,
resizeableItemFrameViewModel = resizeableItemFrameViewModel,
- sceneScope = sceneScope,
+ contentScope = contentScope,
)
}
}
@@ -1261,7 +1261,7 @@ private fun CommunalContent(
interactionHandler: RemoteViews.InteractionHandler?,
widgetSection: CommunalAppWidgetSection,
resizeableItemFrameViewModel: ResizeableItemFrameViewModel,
- sceneScope: SceneScope? = null,
+ contentScope: ContentScope? = null,
) {
when (model) {
is CommunalContentModel.WidgetContent.Widget ->
@@ -1285,7 +1285,7 @@ private fun CommunalContent(
is CommunalContentModel.CtaTileInViewMode -> CtaTileInViewModeContent(viewModel, modifier)
is CommunalContentModel.Smartspace -> SmartspaceContent(interactionHandler, model, modifier)
is CommunalContentModel.Tutorial -> TutorialContent(modifier)
- is CommunalContentModel.Umo -> Umo(viewModel, sceneScope, modifier)
+ is CommunalContentModel.Umo -> Umo(viewModel, contentScope, modifier)
is CommunalContentModel.Spacer -> Box(Modifier.fillMaxSize())
}
}
@@ -1451,7 +1451,6 @@ private fun WidgetContent(
} else {
Modifier
}
-
Box(
modifier =
modifier
@@ -1539,7 +1538,10 @@ private fun WidgetContent(
with(widgetSection) {
Widget(
isFocusable = isFocusable,
- openWidgetEditor = { viewModel.onOpenWidgetEditor() },
+ openWidgetEditor = {
+ viewModel.setSelectedKey(model.key)
+ viewModel.onOpenWidgetEditor()
+ },
model = model,
size = size,
modifier = Modifier.fillMaxSize().allowGestures(allowed = !viewModel.isEditMode),
@@ -1701,11 +1703,11 @@ private fun TutorialContent(modifier: Modifier = Modifier) {
@Composable
private fun Umo(
viewModel: BaseCommunalViewModel,
- sceneScope: SceneScope?,
+ contentScope: ContentScope?,
modifier: Modifier = Modifier,
) {
- if (SceneContainerFlag.isEnabled && sceneScope != null) {
- sceneScope.MediaCarousel(
+ if (SceneContainerFlag.isEnabled && contentScope != null) {
+ contentScope.MediaCarousel(
modifier = modifier.fillMaxSize(),
isVisible = true,
mediaHost = viewModel.mediaHost,
@@ -1788,6 +1790,7 @@ fun AccessibilityContainer(viewModel: BaseCommunalViewModel, content: @Composabl
CustomAccessibilityAction(
context.getString(R.string.accessibility_action_label_edit_widgets)
) {
+ viewModel.setSelectedKey(null)
viewModel.onOpenWidgetEditor()
true
},
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt
index 88b651019c4a..143fbe4de550 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt
@@ -20,7 +20,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.communal.shared.model.CommunalBackgroundType
@@ -55,7 +55,7 @@ constructor(
}
@Composable
- override fun SceneScope.Content(modifier: Modifier) {
+ override fun ContentScope.Content(modifier: Modifier) {
val backgroundType by
contentViewModel.communalBackground.collectAsStateWithLifecycle(
initialValue = CommunalBackgroundType.ANIMATED
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalTouchableSurface.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalTouchableSurface.kt
index f2edec657cd4..3ae50369e9e3 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalTouchableSurface.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalTouchableSurface.kt
@@ -27,9 +27,14 @@ import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.onPreviewKeyEvent
import androidx.compose.ui.input.pointer.motionEventSpy
-import androidx.compose.ui.semantics.hideFromAccessibility
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.semantics.CustomAccessibilityAction
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.customActions
import androidx.compose.ui.semantics.semantics
+import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
+import com.android.systemui.res.R
@OptIn(ExperimentalFoundationApi::class, ExperimentalComposeUiApi::class)
@Composable
@@ -38,15 +43,38 @@ fun CommunalTouchableSurface(
modifier: Modifier = Modifier,
content: @Composable BoxScope.() -> Unit,
) {
-
+ val context = LocalContext.current
val interactionSource = remember { MutableInteractionSource() }
Box(
modifier =
modifier
- // The touchable surface is hidden for accessibility because these actions are
- // already provided through custom accessibility actions.
- .semantics { hideFromAccessibility() }
+ .semantics {
+ contentDescription =
+ context.getString(
+ R.string.accessibility_content_description_for_communal_hub
+ )
+ customActions =
+ listOf(
+ CustomAccessibilityAction(
+ context.getString(
+ R.string.accessibility_action_label_close_communal_hub
+ )
+ ) {
+ viewModel.changeScene(
+ CommunalScenes.Blank,
+ "closed by accessibility",
+ )
+ true
+ },
+ CustomAccessibilityAction(
+ context.getString(R.string.accessibility_action_label_edit_widgets)
+ ) {
+ viewModel.onOpenWidgetEditor()
+ true
+ },
+ )
+ }
.combinedClickable(
onLongClick = viewModel::onLongClick,
onClick = viewModel::onClick,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/AmbientStatusBarSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/AmbientStatusBarSection.kt
index 3b335fa3141e..1b0ddcb13ee2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/AmbientStatusBarSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/AmbientStatusBarSection.kt
@@ -22,7 +22,7 @@ import android.widget.FrameLayout
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidView
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.systemui.ambient.statusbar.dagger.AmbientStatusBarComponent
import com.android.systemui.ambient.statusbar.ui.AmbientStatusBarView
import com.android.systemui.communal.ui.compose.Communal
@@ -31,11 +31,9 @@ import javax.inject.Inject
class AmbientStatusBarSection
@Inject
-constructor(
- private val factory: AmbientStatusBarComponent.Factory,
-) {
+constructor(private val factory: AmbientStatusBarComponent.Factory) {
@Composable
- fun SceneScope.AmbientStatusBar(modifier: Modifier = Modifier) {
+ fun ContentScope.AmbientStatusBar(modifier: Modifier = Modifier) {
AndroidView(
factory = { context ->
(LayoutInflater.from(context)
@@ -49,7 +47,7 @@ constructor(
factory.create(this).getController().apply { init() }
}
},
- modifier = modifier.element(Communal.Elements.StatusBar)
+ modifier = modifier.element(Communal.Elements.StatusBar),
)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/dream/ui/composable/DreamScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/dream/ui/composable/DreamScene.kt
index f4374c6c9487..6cd0c5dfd15c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/dream/ui/composable/DreamScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/dream/ui/composable/DreamScene.kt
@@ -24,7 +24,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.dagger.SysUISingleton
@@ -54,7 +54,7 @@ constructor(private val actionsViewModelFactory: DreamUserActionsViewModel.Facto
}
@Composable
- override fun SceneScope.Content(modifier: Modifier) {
+ override fun ContentScope.Content(modifier: Modifier) {
Box(modifier = modifier.fillMaxSize()) {
// Render a sleep emoji to make the scene appear visible.
Text(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
index 5c5514aec03e..7b2f9dc76158 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
@@ -24,7 +24,7 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalView
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint
@@ -50,7 +50,7 @@ class LockscreenContent(
}
@Composable
- fun SceneScope.Content(modifier: Modifier = Modifier) {
+ fun ContentScope.Content(modifier: Modifier = Modifier) {
val viewModel =
rememberViewModel("LockscreenContent-viewModel") { viewModelFactory.create() }
val notificationLockscreenScrimViewModel =
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
index c7c29f9fdb7c..5e61af634bbc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
@@ -19,7 +19,7 @@ package com.android.systemui.keyguard.ui.composable
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.animateContentFloatAsState
@@ -54,18 +54,13 @@ constructor(
}
@Composable
- override fun SceneScope.Content(
- modifier: Modifier,
- ) {
- LockscreenScene(
- lockscreenContent = lockscreenContent,
- modifier = modifier,
- )
+ override fun ContentScope.Content(modifier: Modifier) {
+ LockscreenScene(lockscreenContent = lockscreenContent, modifier = modifier)
}
}
@Composable
-private fun SceneScope.LockscreenScene(
+private fun ContentScope.LockscreenScene(
lockscreenContent: Lazy<LockscreenContent>,
modifier: Modifier = Modifier,
) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/CommunalBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/CommunalBlueprint.kt
index adad4468b751..c365ec590a5f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/CommunalBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/CommunalBlueprint.kt
@@ -23,7 +23,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
import dagger.Binds
@@ -37,14 +37,8 @@ class CommunalBlueprint @Inject constructor() : ComposableLockscreenSceneBluepri
override val id: String = "communal"
@Composable
- override fun SceneScope.Content(
- viewModel: LockscreenContentViewModel,
- modifier: Modifier,
- ) {
- LockscreenLongPress(
- viewModel = viewModel.touchHandling,
- modifier = modifier,
- ) { _ ->
+ override fun ContentScope.Content(viewModel: LockscreenContentViewModel, modifier: Modifier) {
+ LockscreenLongPress(viewModel = viewModel.touchHandling, modifier = modifier) { _ ->
Box(modifier.background(Color.Black)) {
Text(
text = "TODO(b/316211368): communal blueprint",
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ComposableLockscreenSceneBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ComposableLockscreenSceneBlueprint.kt
index df36d0774f11..cfafb6214c45 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ComposableLockscreenSceneBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ComposableLockscreenSceneBlueprint.kt
@@ -18,16 +18,12 @@ package com.android.systemui.keyguard.ui.composable.blueprint
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.systemui.keyguard.shared.model.LockscreenSceneBlueprint
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
/** Defines interface for classes that can render the content for a specific blueprint/layout. */
interface ComposableLockscreenSceneBlueprint : LockscreenSceneBlueprint {
/** Renders the content of this blueprint. */
- @Composable
- fun SceneScope.Content(
- viewModel: LockscreenContentViewModel,
- modifier: Modifier,
- )
+ @Composable fun ContentScope.Content(viewModel: LockscreenContentViewModel, modifier: Modifier)
}
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 9643f192e066..c55a3fdfc6c0 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
@@ -32,7 +32,7 @@ import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntRect
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.modifiers.padding
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
@@ -68,7 +68,7 @@ constructor(
override val id: String = "default"
@Composable
- override fun SceneScope.Content(viewModel: LockscreenContentViewModel, modifier: Modifier) {
+ override fun ContentScope.Content(viewModel: LockscreenContentViewModel, modifier: Modifier) {
val isUdfpsVisible = viewModel.isUdfpsVisible
val isShadeLayoutWide by viewModel.isShadeLayoutWide.collectAsStateWithLifecycle()
val unfoldTranslations by viewModel.unfoldTranslations.collectAsStateWithLifecycle()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/AmbientIndicationSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/AmbientIndicationSection.kt
index af9a195c4575..99a7633e3cd3 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/AmbientIndicationSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/AmbientIndicationSection.kt
@@ -18,9 +18,9 @@ package com.android.systemui.keyguard.ui.composable.section
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
/** Defines interface for classes that can render the ambient indication area. */
interface AmbientIndicationSection {
- @Composable fun SceneScope.AmbientIndication(modifier: Modifier)
+ @Composable fun ContentScope.AmbientIndication(modifier: Modifier)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt
index 5e9ade163ac2..52ccab3b4d1e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt
@@ -30,8 +30,8 @@ import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.content.res.ResourcesCompat
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.SceneScope
import com.android.systemui.animation.view.LaunchableImageView
import com.android.systemui.keyguard.ui.binder.KeyguardIndicationAreaBinder
import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
@@ -61,7 +61,7 @@ constructor(
* shortcut is placed along the edges of the display.
*/
@Composable
- fun SceneScope.Shortcut(
+ fun ContentScope.Shortcut(
isStart: Boolean,
applyPadding: Boolean,
modifier: Modifier = Modifier,
@@ -89,7 +89,7 @@ constructor(
}
@Composable
- fun SceneScope.IndicationArea(modifier: Modifier = Modifier) {
+ fun ContentScope.IndicationArea(modifier: Modifier = Modifier) {
Element(key = IndicationAreaElementKey, modifier = modifier.indicationAreaPadding()) {
content {
IndicationArea(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
index fb01e7039edd..34c0bcaca997 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
@@ -32,7 +32,7 @@ import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.view.contains
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.modifiers.padding
import com.android.systemui.customization.R
import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys.largeClockElementKey
@@ -54,7 +54,7 @@ constructor(
private val aodBurnInViewModel: AodBurnInViewModel,
) {
@Composable
- fun SceneScope.SmallClock(
+ fun ContentScope.SmallClock(
burnInParams: BurnInParameters,
onTopChanged: (top: Float?) -> Unit,
modifier: Modifier = Modifier,
@@ -87,7 +87,7 @@ constructor(
}
@Composable
- fun SceneScope.LargeClock(burnInParams: BurnInParameters, modifier: Modifier = Modifier) {
+ fun ContentScope.LargeClock(burnInParams: BurnInParameters, modifier: Modifier = Modifier) {
val currentClock by viewModel.currentClock.collectAsStateWithLifecycle()
if (currentClock?.largeClock?.view == null) {
return
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
index 597cbf24729b..4795e7cef87c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
@@ -28,8 +28,8 @@ import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.viewinterop.AndroidView
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.SceneScope
import com.android.systemui.biometrics.AuthController
import com.android.systemui.customization.R as customR
import com.android.systemui.dagger.qualifiers.Application
@@ -66,7 +66,7 @@ constructor(
@LongPressTouchLog private val logBuffer: LogBuffer,
) {
@Composable
- fun SceneScope.LockIcon(overrideColor: Color? = null, modifier: Modifier = Modifier) {
+ fun ContentScope.LockIcon(overrideColor: Color? = null, modifier: Modifier = Modifier) {
val context = LocalContext.current
AndroidView(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
index 4a9f44b74099..0ff567bf90ad 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
@@ -23,7 +23,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.dimensionResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.systemui.keyguard.ui.viewmodel.KeyguardMediaViewModel
import com.android.systemui.media.controls.ui.composable.MediaCarousel
import com.android.systemui.media.controls.ui.controller.MediaCarouselController
@@ -42,7 +42,7 @@ constructor(
) {
@Composable
- fun SceneScope.KeyguardMediaCarousel(
+ fun ContentScope.KeyguardMediaCarousel(
isShadeLayoutWide: Boolean,
modifier: Modifier = Modifier,
) {
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 0344ab8e0196..2bc392d386bf 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
@@ -34,7 +34,7 @@ import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.modifiers.thenIf
import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.dagger.SysUISingleton
@@ -148,7 +148,7 @@ constructor(
}
@Composable
- fun SceneScope.HeadsUpNotifications() {
+ fun ContentScope.HeadsUpNotifications() {
SnoozeableHeadsUpNotificationSpace(
stackScrollView = stackScrollView.get(),
viewModel = rememberViewModel("HeadsUpNotifications") { viewModelFactory.create() },
@@ -160,7 +160,7 @@ constructor(
* adjustment
*/
@Composable
- fun SceneScope.Notifications(
+ fun ContentScope.Notifications(
areNotificationsVisible: Boolean,
isShadeLayoutWide: Boolean,
burnInParams: BurnInParameters?,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt
index 1cee4d67df3b..c3ba7ab2fd19 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt
@@ -35,7 +35,7 @@ import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.modifiers.padding
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys
@@ -57,7 +57,7 @@ constructor(
private val aodBurnInViewModel: AodBurnInViewModel,
) {
@Composable
- fun SceneScope.SmartSpace(
+ fun ContentScope.SmartSpace(
burnInParams: BurnInParameters,
onTopChanged: (top: Float?) -> Unit,
smartSpacePaddingTop: (Resources) -> Int,
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 0d8a47019a08..172c3f5a1135 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
@@ -26,7 +26,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.viewinterop.AndroidView
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.modifiers.height
import com.android.keyguard.dagger.KeyguardStatusBarViewComponent
import com.android.systemui.common.ui.compose.windowinsets.LocalDisplayCutout
@@ -45,9 +45,10 @@ constructor(
private val notificationPanelView: Lazy<NotificationPanelView>,
) {
@Composable
- fun SceneScope.StatusBar(modifier: Modifier = Modifier) {
+ fun ContentScope.StatusBar(modifier: Modifier = Modifier) {
val context = LocalContext.current
val viewDisplayCutout = LocalDisplayCutout.current.viewDisplayCutoutKeyguardStatusBarView
+
@SuppressLint("InflateParams")
val view =
remember(context) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
index 73c4fab7b646..6250da379402 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
@@ -30,9 +30,8 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.viewinterop.AndroidView
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.SceneScope
-import com.android.compose.modifiers.padding
import com.android.systemui.customization.R as customR
import com.android.systemui.keyguard.ui.composable.blueprint.WeatherClockElementKeys
import com.android.systemui.keyguard.ui.composable.modifier.burnInAware
@@ -50,15 +49,10 @@ constructor(
private val aodBurnInViewModel: AodBurnInViewModel,
) {
@Composable
- fun SceneScope.Time(
- clock: ClockController,
- burnInParams: BurnInParameters,
- ) {
+ fun ContentScope.Time(clock: ClockController, burnInParams: BurnInParameters) {
Row(
modifier =
- Modifier.padding(
- horizontal = dimensionResource(customR.dimen.clock_padding_start)
- )
+ Modifier.padding(horizontal = dimensionResource(customR.dimen.clock_padding_start))
.burnInAware(aodBurnInViewModel, burnInParams, isClock = true)
) {
WeatherElement(
@@ -70,10 +64,7 @@ constructor(
}
@Composable
- private fun SceneScope.Date(
- clock: ClockController,
- modifier: Modifier = Modifier,
- ) {
+ private fun ContentScope.Date(clock: ClockController, modifier: Modifier = Modifier) {
WeatherElement(
weatherClockElementViewId = customR.id.weather_clock_date,
clock = clock,
@@ -83,10 +74,7 @@ constructor(
}
@Composable
- private fun SceneScope.Weather(
- clock: ClockController,
- modifier: Modifier = Modifier,
- ) {
+ private fun ContentScope.Weather(clock: ClockController, modifier: Modifier = Modifier) {
WeatherElement(
weatherClockElementViewId = customR.id.weather_clock_weather_icon,
clock = clock,
@@ -96,10 +84,7 @@ constructor(
}
@Composable
- private fun SceneScope.DndAlarmStatus(
- clock: ClockController,
- modifier: Modifier = Modifier,
- ) {
+ private fun ContentScope.DndAlarmStatus(clock: ClockController, modifier: Modifier = Modifier) {
WeatherElement(
weatherClockElementViewId = customR.id.weather_clock_alarm_dnd,
clock = clock,
@@ -109,10 +94,7 @@ constructor(
}
@Composable
- private fun SceneScope.Temperature(
- clock: ClockController,
- modifier: Modifier = Modifier,
- ) {
+ private fun ContentScope.Temperature(clock: ClockController, modifier: Modifier = Modifier) {
WeatherElement(
weatherClockElementViewId = customR.id.weather_clock_temperature,
clock = clock,
@@ -122,7 +104,7 @@ constructor(
}
@Composable
- private fun SceneScope.WeatherElement(
+ private fun ContentScope.WeatherElement(
weatherClockElementViewId: Int,
clock: ClockController,
elementKey: ElementKey,
@@ -144,32 +126,28 @@ constructor(
}
},
update = {},
- modifier = modifier
+ modifier = modifier,
)
}
}
}
@Composable
- fun SceneScope.LargeClockSectionBelowSmartspace(
+ fun ContentScope.LargeClockSectionBelowSmartspace(
burnInParams: BurnInParameters,
clock: ClockController,
) {
Row(
modifier =
Modifier.height(IntrinsicSize.Max)
- .padding(
- horizontal = dimensionResource(customR.dimen.clock_padding_start)
- )
+ .padding(horizontal = dimensionResource(customR.dimen.clock_padding_start))
.burnInAware(aodBurnInViewModel, burnInParams, isClock = true)
) {
Date(clock = clock, modifier = Modifier.wrapContentSize())
Box(
modifier =
Modifier.fillMaxSize()
- .padding(
- start = dimensionResource(customR.dimen.clock_padding_start)
- )
+ .padding(start = dimensionResource(customR.dimen.clock_padding_start))
) {
Weather(clock = clock, modifier = Modifier.align(Alignment.TopStart))
Temperature(clock = clock, modifier = Modifier.align(Alignment.BottomEnd))
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 b5d78398028d..f5de7dca6d9d 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
@@ -31,8 +31,8 @@ import androidx.compose.ui.layout.layout
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.viewinterop.AndroidView
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.MovableElementKey
-import com.android.compose.animation.scene.SceneScope
import com.android.compose.windowsizeclass.LocalWindowSizeClass
import com.android.systemui.media.controls.ui.composable.MediaCarouselStateLoader.stateForMediaCarouselContent
import com.android.systemui.media.controls.ui.controller.MediaCarouselController
@@ -52,7 +52,7 @@ object MediaCarousel {
}
@Composable
-fun SceneScope.MediaCarousel(
+fun ContentScope.MediaCarousel(
isVisible: Boolean,
mediaHost: MediaHost,
modifier: Modifier = Modifier,
@@ -136,6 +136,6 @@ private fun ViewGroup.setView(view: View) {
}
@Composable
-fun SceneScope.isLandscape(): Boolean {
+fun ContentScope.isLandscape(): Boolean {
return LocalWindowSizeClass.current.heightSizeClass == WindowHeightSizeClass.Compact
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarouselStateLoader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarouselStateLoader.kt
index bad74052b669..525284207744 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarouselStateLoader.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarouselStateLoader.kt
@@ -17,8 +17,8 @@
package com.android.systemui.media.controls.ui.composable
import com.android.compose.animation.scene.ContentKey
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.SceneKey
-import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.systemui.media.controls.ui.controller.MediaCarouselController
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager
@@ -50,6 +50,7 @@ object MediaCarouselStateLoader {
if (isSplitShade) MediaHierarchyManager.LOCATION_QS
else MediaHierarchyManager.LOCATION_QQS
}
+
Scenes.Lockscreen -> MediaHierarchyManager.LOCATION_LOCKSCREEN
Scenes.Communal -> MediaHierarchyManager.LOCATION_COMMUNAL_HUB
else -> MediaHierarchyManager.LOCATION_UNKNOWN
@@ -69,6 +70,7 @@ object MediaCarouselStateLoader {
/** State for media carousel. */
sealed interface State {
val transitionProgress: Float
+
// TODO b/368368388: implement media squishiness
val squishFraction: () -> Float
@MediaLocation val startLocation: Int
@@ -100,7 +102,7 @@ object MediaCarouselStateLoader {
}
/** Returns the state of media carousel */
- fun SceneScope.stateForMediaCarouselContent(isInSplitShade: Boolean): State {
+ fun ContentScope.stateForMediaCarouselContent(isInSplitShade: Boolean): State {
return when (val transitionState = layoutState.transitionState) {
is TransitionState.Idle -> {
if (MediaContentPicker.contents.contains(transitionState.currentScene)) {
@@ -109,6 +111,7 @@ object MediaCarouselStateLoader {
State.Gone
}
}
+
is TransitionState.Transition.ChangeScene ->
with(transitionState) {
if (
@@ -130,6 +133,7 @@ object MediaCarouselStateLoader {
State.Gone
}
}
+
is TransitionState.Transition.OverlayTransition ->
with(transitionState) {
if (
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt
index d52323295db7..215a43382b06 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt
@@ -24,7 +24,6 @@ import com.android.compose.animation.scene.StaticElementContentPicker
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.shade.shared.flag.DualShade
/** [ElementContentPicker] implementation for the media carousel object. */
object MediaContentPicker : StaticElementContentPicker {
@@ -46,8 +45,11 @@ object MediaContentPicker : StaticElementContentPicker {
toContentZIndex: Float,
): ContentKey {
return when {
- shouldElevateMedia(transition) -> {
- if (DualShade.isEnabled) Overlays.NotificationsShade else Scenes.Shade
+ transition.isTransitioningBetween(Scenes.Lockscreen, Scenes.Shade) -> {
+ Scenes.Shade
+ }
+ transition.isTransitioningBetween(Scenes.Lockscreen, Overlays.NotificationsShade) -> {
+ Overlays.NotificationsShade
}
transition.isTransitioningBetween(Scenes.Lockscreen, Scenes.Communal) -> {
Scenes.Lockscreen
@@ -71,14 +73,12 @@ object MediaContentPicker : StaticElementContentPicker {
}
}
}
-
- /** Returns true when the media should be laid on top of the rest for the given [transition]. */
- fun shouldElevateMedia(transition: TransitionState.Transition): Boolean {
- return transition.isTransitioningBetween(Scenes.Lockscreen, Scenes.Shade) ||
- transition.isTransitioningBetween(Scenes.Lockscreen, Overlays.NotificationsShade)
- }
}
+/** Whether media should be laid on top of the rest for the given [transition]. */
fun MediaContentPicker.shouldElevateMedia(layoutState: SceneTransitionLayoutState): Boolean {
- return layoutState.currentTransition?.let { shouldElevateMedia(it) } ?: false
+ return layoutState.currentTransition?.let { transition ->
+ transition.isTransitioningBetween(Scenes.Lockscreen, Scenes.Shade) ||
+ transition.isTransitioningBetween(Scenes.Lockscreen, Overlays.NotificationsShade)
+ } ?: false
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
index 183929ca6c6a..a6918a7c5ffe 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
@@ -96,9 +96,7 @@ import com.android.systemui.common.ui.compose.windowinsets.LocalScreenCornerRadi
import com.android.systemui.res.R
import com.android.systemui.scene.session.ui.composable.SaveableSession
import com.android.systemui.scene.session.ui.composable.rememberSession
-import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.shade.ui.composable.ShadeHeader
import com.android.systemui.statusbar.notification.stack.shared.model.AccessibilityScrollEvent
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds
@@ -124,12 +122,6 @@ object Notifications {
}
}
-private val notificationsShadeContentKey: ContentKey
- get() = if (DualShade.isEnabled) Overlays.NotificationsShade else Scenes.Shade
-
-private val quickSettingsShadeContentKey: ContentKey
- get() = if (DualShade.isEnabled) Overlays.QuickSettingsShade else Scenes.QuickSettings
-
/**
* Adds the space where heads up notifications can appear in the scene. This should generally be the
* entire size of the scene.
@@ -270,7 +262,12 @@ fun ContentScope.ConstrainedNotificationStack(
HeadsUpNotificationSpace(
stackScrollView = stackScrollView,
viewModel = viewModel,
- useHunBounds = { shouldUseLockscreenHunBounds(layoutState.transitionState) },
+ useHunBounds = {
+ shouldUseLockscreenHunBounds(
+ layoutState.transitionState,
+ viewModel.quickSettingsShadeContentKey,
+ )
+ },
modifier = Modifier.align(Alignment.TopCenter),
)
NotificationStackCutoffGuideline(
@@ -494,11 +491,11 @@ fun ContentScope.NotificationScrollingStack(
if (
scrimOffset.value < 0 &&
(layoutState.isTransitioning(
- from = notificationsShadeContentKey,
+ from = viewModel.notificationsShadeContentKey,
to = Scenes.Gone,
) ||
layoutState.isTransitioning(
- from = notificationsShadeContentKey,
+ from = viewModel.notificationsShadeContentKey,
to = Scenes.Lockscreen,
))
) {
@@ -527,6 +524,7 @@ fun ContentScope.NotificationScrollingStack(
shouldAnimateScrimCornerRadius(
layoutState,
shouldPunchHoleBehindScrim,
+ viewModel.notificationsShadeContentKey,
),
)
.let { scrimRounding.value.toRoundedCornerShape(it) }
@@ -613,7 +611,12 @@ fun ContentScope.NotificationScrollingStack(
HeadsUpNotificationSpace(
stackScrollView = stackScrollView,
viewModel = viewModel,
- useHunBounds = { !shouldUseLockscreenHunBounds(layoutState.transitionState) },
+ useHunBounds = {
+ !shouldUseLockscreenHunBounds(
+ layoutState.transitionState,
+ viewModel.quickSettingsShadeContentKey,
+ )
+ },
modifier = Modifier.padding(top = stackTopPadding),
)
}
@@ -720,20 +723,24 @@ private fun shouldUseLockscreenStackBounds(state: TransitionState): Boolean {
return state is TransitionState.Idle && state.isOnLockscreen()
}
-private fun shouldUseLockscreenHunBounds(state: TransitionState): Boolean {
+private fun shouldUseLockscreenHunBounds(
+ state: TransitionState,
+ quickSettingsShade: ContentKey,
+): Boolean {
return when (state) {
is TransitionState.Idle -> state.isOnLockscreen()
is TransitionState.Transition ->
- state.isTransitioning(from = quickSettingsShadeContentKey, to = Scenes.Lockscreen)
+ state.isTransitioning(from = quickSettingsShade, to = Scenes.Lockscreen)
}
}
private fun shouldAnimateScrimCornerRadius(
state: SceneTransitionLayoutState,
shouldPunchHoleBehindScrim: Boolean,
+ notificationsShade: ContentKey,
): Boolean {
return shouldPunchHoleBehindScrim ||
- state.isTransitioning(from = notificationsShadeContentKey, to = Scenes.Lockscreen)
+ state.isTransitioning(from = notificationsShade, to = Scenes.Lockscreen)
}
private fun calculateCornerRadius(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
index f7ce2153b0ec..25b673bee1cd 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
@@ -72,9 +72,10 @@ import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.compose.animation.Expandable
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.modifiers.fadingBackground
import com.android.compose.theme.colorAttr
+import com.android.systemui.Flags.notificationShadeBlur
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.ui.compose.Icon
@@ -90,7 +91,7 @@ import com.android.systemui.res.R
import kotlinx.coroutines.launch
@Composable
-fun SceneScope.FooterActionsWithAnimatedVisibility(
+fun ContentScope.FooterActionsWithAnimatedVisibility(
viewModel: FooterActionsViewModel,
isCustomizing: Boolean,
customizingAnimationDuration: Int,
@@ -163,14 +164,16 @@ fun FooterActions(
}
}
- val backgroundColor = colorAttr(R.attr.underSurface)
+ val backgroundColor =
+ if (!notificationShadeBlur()) colorAttr(R.attr.underSurface) else Color.Transparent
+ val backgroundAlphaValue = if (!notificationShadeBlur()) backgroundAlpha::value else ({ 0f })
val contentColor = MaterialTheme.colorScheme.onSurface
val backgroundTopRadius = dimensionResource(R.dimen.qs_corner_radius)
val backgroundModifier =
- remember(backgroundColor, backgroundAlpha, backgroundTopRadius) {
+ remember(backgroundColor, backgroundAlphaValue, backgroundTopRadius) {
Modifier.fadingBackground(
backgroundColor,
- backgroundAlpha::value,
+ backgroundAlphaValue,
RoundedCornerShape(topStart = backgroundTopRadius, topEnd = backgroundTopRadius),
)
}
@@ -253,6 +256,7 @@ private fun RowScope.ForegroundServicesButton(
} else {
NumberButton(
model.foregroundServicesCount,
+ contentDescription = model.text,
showNewDot = model.hasNewChanges,
onClick = model.onClick,
)
@@ -281,6 +285,7 @@ fun IconButton(model: FooterActionsButtonViewModel, modifier: Modifier = Modifie
@Composable
private fun NumberButton(
number: Int,
+ contentDescription: String,
showNewDot: Boolean,
onClick: (Expandable) -> Unit,
modifier: Modifier = Modifier,
@@ -311,7 +316,10 @@ private fun NumberButton(
) {
Text(
number.toString(),
- modifier = Modifier.align(Alignment.Center),
+ modifier =
+ Modifier.align(Alignment.Center).semantics {
+ this.contentDescription = contentDescription
+ },
style = MaterialTheme.typography.bodyLarge,
color = colorAttr(R.attr.onShadeInactiveVariant),
// TODO(b/242040009): This should only use a standard text style instead and
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
index 58336c2e9d41..b826187578e0 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
@@ -36,10 +36,10 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.MovableElementContentPicker
import com.android.compose.animation.scene.MovableElementKey
-import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.SceneTransitionLayoutState
import com.android.compose.animation.scene.ValueKey
import com.android.compose.animation.scene.content.state.TransitionState
@@ -98,7 +98,7 @@ object QuickSettings {
}
}
-private fun SceneScope.stateForQuickSettingsContent(
+private fun ContentScope.stateForQuickSettingsContent(
isSplitShade: Boolean,
squishiness: () -> Float = { QuickSettings.SharedValues.SquishinessValues.Default },
): QSSceneAdapter.State {
@@ -141,7 +141,7 @@ private fun SceneScope.stateForQuickSettingsContent(
/**
* This composable will show QuickSettingsContent in the correct state (as determined by its
- * [SceneScope]).
+ * [ContentScope]).
*
* If adding to scenes not in:
* * QuickSettingsScene
@@ -153,7 +153,7 @@ private fun SceneScope.stateForQuickSettingsContent(
* * this doc.
*/
@Composable
-fun SceneScope.QuickSettings(
+fun ContentScope.QuickSettings(
qsSceneAdapter: QSSceneAdapter,
heightProvider: () -> Int,
isSplitShade: Boolean,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 26cf7066124a..4bfbb3a908fa 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -68,7 +68,7 @@ import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.animateSceneDpAsState
@@ -144,7 +144,7 @@ constructor(
}
@Composable
- override fun SceneScope.Content(modifier: Modifier) {
+ override fun ContentScope.Content(modifier: Modifier) {
QuickSettingsScene(
notificationStackScrollView = notificationStackScrollView.get(),
viewModelFactory = contentViewModelFactory,
@@ -164,7 +164,7 @@ constructor(
}
@Composable
-private fun SceneScope.QuickSettingsScene(
+private fun ContentScope.QuickSettingsScene(
notificationStackScrollView: NotificationScrollView,
viewModelFactory: QuickSettingsSceneContentViewModel.Factory,
notificationsPlaceholderViewModel: NotificationsPlaceholderViewModel,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
index f052e60246d2..50bae8a094ad 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
@@ -31,10 +31,14 @@ import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.boundsInWindow
+import androidx.compose.ui.layout.onPlaced
+import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ContentScope
@@ -59,6 +63,8 @@ import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.ui.composable.Overlay
import com.android.systemui.shade.ui.composable.CollapsedShadeHeader
import com.android.systemui.shade.ui.composable.OverlayShade
+import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds
+import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape
import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
import com.android.systemui.statusbar.phone.ui.StatusBarIconController
@@ -96,13 +102,37 @@ constructor(
override fun ContentScope.Content(modifier: Modifier) {
val viewModel =
rememberViewModel("QuickSettingsShadeOverlay") { contentViewModelFactory.create() }
+ val panelCornerRadius =
+ with(LocalDensity.current) { OverlayShade.Dimensions.PanelCornerRadius.toPx().toInt() }
+
+ // set the bounds to null when the QuickSettings overlay disappears
+ DisposableEffect(Unit) { onDispose { viewModel.onPanelShapeChanged(null) } }
OverlayShade(
panelAlignment = Alignment.TopEnd,
modifier = modifier,
onScrimClicked = viewModel::onScrimClicked,
) {
- Column {
+ Column(
+ modifier =
+ Modifier.onPlaced { coordinates ->
+ val boundsInWindow = coordinates.boundsInWindow()
+ val shadeScrimBounds =
+ ShadeScrimBounds(
+ left = boundsInWindow.left,
+ top = boundsInWindow.top,
+ right = boundsInWindow.right,
+ bottom = boundsInWindow.bottom,
+ )
+ val shape =
+ ShadeScrimShape(
+ bounds = shadeScrimBounds,
+ topRadius = 0,
+ bottomRadius = panelCornerRadius,
+ )
+ viewModel.onPanelShapeChanged(shape)
+ }
+ ) {
if (viewModel.showHeader) {
CollapsedShadeHeader(
viewModelFactory = viewModel.shadeHeaderViewModelFactory,
@@ -112,7 +142,6 @@ constructor(
statusBarIconController = statusBarIconController,
)
}
-
ShadeBody(viewModel = viewModel.quickSettingsContainerViewModel)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
index 9ee25c3404ec..2175a59e8e4d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
@@ -25,7 +25,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.animateContentDpAsState
@@ -71,7 +71,7 @@ constructor(
}
@Composable
- override fun SceneScope.Content(modifier: Modifier) {
+ override fun ContentScope.Content(modifier: Modifier) {
val isIdleAndNotOccluded by remember {
derivedStateOf {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/Scene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/Scene.kt
index 8d8ab8ee7949..6c80c69b7a34 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/Scene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/Scene.kt
@@ -18,8 +18,8 @@ package com.android.systemui.scene.ui.composable
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.SceneKey
-import com.android.compose.animation.scene.SceneScope
import com.android.systemui.lifecycle.Activatable
/**
@@ -35,5 +35,5 @@ interface Scene : Activatable, ActionableContent {
/** Uniquely-identifying key for this scene. The key must be unique within its container. */
val key: SceneKey
- @Composable fun SceneScope.Content(modifier: Modifier)
+ @Composable fun ContentScope.Content(modifier: Modifier)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
index bfcde7dab6d2..3131b539c6af 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
@@ -58,9 +58,9 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.max
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.LowestZIndexContentPicker
-import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.ValueKey
import com.android.compose.animation.scene.animateElementFloatAsState
import com.android.compose.animation.scene.content.state.TransitionState
@@ -122,7 +122,7 @@ object ShadeHeader {
}
@Composable
-fun SceneScope.CollapsedShadeHeader(
+fun ContentScope.CollapsedShadeHeader(
viewModelFactory: ShadeHeaderViewModel.Factory,
createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager,
createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController,
@@ -264,7 +264,7 @@ fun SceneScope.CollapsedShadeHeader(
}
@Composable
-fun SceneScope.ExpandedShadeHeader(
+fun ContentScope.ExpandedShadeHeader(
viewModelFactory: ShadeHeaderViewModel.Factory,
createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager,
createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController,
@@ -339,7 +339,7 @@ fun SceneScope.ExpandedShadeHeader(
}
@Composable
-private fun SceneScope.Clock(scale: Float, viewModel: ShadeHeaderViewModel, modifier: Modifier) {
+private fun ContentScope.Clock(scale: Float, viewModel: ShadeHeaderViewModel, modifier: Modifier) {
val layoutDirection = LocalLayoutDirection.current
Element(key = ShadeHeader.Elements.Clock, modifier = modifier) {
@@ -446,7 +446,7 @@ private fun ShadeCarrierGroup(viewModel: ShadeHeaderViewModel, modifier: Modifie
}
@Composable
-private fun SceneScope.StatusIcons(
+private fun ContentScope.StatusIcons(
viewModel: ShadeHeaderViewModel,
createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager,
statusBarIconController: StatusBarIconController,
@@ -548,7 +548,10 @@ private fun SystemIconContainer(
}
@Composable
-private fun SceneScope.PrivacyChip(viewModel: ShadeHeaderViewModel, modifier: Modifier = Modifier) {
+private fun ContentScope.PrivacyChip(
+ viewModel: ShadeHeaderViewModel,
+ modifier: Modifier = Modifier,
+) {
val privacyList by viewModel.privacyItems.collectAsStateWithLifecycle()
AndroidView(
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 0d3bab24f68f..f829a0d6facf 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
@@ -62,9 +62,9 @@ import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.LowestZIndexContentPicker
-import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.animateContentDpAsState
@@ -160,7 +160,7 @@ constructor(
override val userActions: Flow<Map<UserAction, UserActionResult>> = actionsViewModel.actions
@Composable
- override fun SceneScope.Content(modifier: Modifier) =
+ override fun ContentScope.Content(modifier: Modifier) =
ShadeScene(
notificationStackScrollView.get(),
viewModel =
@@ -193,7 +193,7 @@ constructor(
}
@Composable
-private fun SceneScope.ShadeScene(
+private fun ContentScope.ShadeScene(
notificationStackScrollView: NotificationScrollView,
viewModel: ShadeSceneContentViewModel,
notificationsPlaceholderViewModel: NotificationsPlaceholderViewModel,
@@ -242,7 +242,7 @@ private fun SceneScope.ShadeScene(
}
@Composable
-private fun SceneScope.SingleShade(
+private fun ContentScope.SingleShade(
notificationStackScrollView: NotificationScrollView,
viewModel: ShadeSceneContentViewModel,
notificationsPlaceholderViewModel: NotificationsPlaceholderViewModel,
@@ -410,7 +410,7 @@ private fun SceneScope.SingleShade(
}
@Composable
-private fun SceneScope.SplitShade(
+private fun ContentScope.SplitShade(
notificationStackScrollView: NotificationScrollView,
viewModel: ShadeSceneContentViewModel,
notificationsPlaceholderViewModel: NotificationsPlaceholderViewModel,
@@ -632,7 +632,7 @@ private fun SceneScope.SplitShade(
}
@Composable
-private fun SceneScope.ShadeMediaCarousel(
+private fun ContentScope.ShadeMediaCarousel(
isVisible: Boolean,
isInRow: Boolean,
mediaHost: MediaHost,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
index 25892c5a75cc..d9e8f02f005b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
@@ -19,7 +19,6 @@ package com.android.systemui.volume.panel.component.volume.ui.composable
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
-import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.tween
@@ -70,8 +69,6 @@ private const val SHRINK_FRACTION = 0.55f
private const val SCALE_FRACTION = 0.9f
private const val EXPAND_BUTTON_SCALE = 0.8f
-/** Volume sliders laid out in a collapsable column */
-@OptIn(ExperimentalAnimationApi::class)
@Composable
fun ColumnVolumeSliders(
viewModels: List<SliderViewModel>,
@@ -144,8 +141,7 @@ fun ColumnVolumeSliders(
VolumeSlider(
modifier =
- Modifier.padding(top = 16.dp)
- .fillMaxWidth()
+ Modifier.fillMaxWidth()
.animateEnterExit(
enter =
enterTransition(
@@ -157,7 +153,10 @@ fun ColumnVolumeSliders(
index = index,
totalCount = viewModels.size,
),
- ),
+ )
+ .thenIf(!Flags.volumeRedesign()) {
+ Modifier.padding(top = 16.dp)
+ },
state = sliderState,
onValueChange = { newValue: Float ->
sliderViewModel.onValueChanged(sliderState, newValue)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt
index 5f991fbb50df..bdd0da9ce4a4 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt
@@ -17,10 +17,12 @@
package com.android.systemui.volume.panel.component.volume.ui.composable
import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
+import androidx.compose.foundation.basicMarquee
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.interaction.MutableInteractionSource
@@ -33,6 +35,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Icon as MaterialIcon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Slider
import androidx.compose.material3.Text
@@ -47,6 +50,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
import androidx.compose.ui.semantics.CustomAccessibilityAction
import androidx.compose.ui.semantics.ProgressBarRangeInfo
import androidx.compose.ui.semantics.clearAndSetSemantics
@@ -67,6 +71,7 @@ import com.android.systemui.haptics.slider.SeekableSliderTrackerConfig
import com.android.systemui.haptics.slider.SliderHapticFeedbackConfig
import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
import com.android.systemui.lifecycle.rememberViewModel
+import com.android.systemui.res.R
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderState
import kotlin.math.round
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -98,7 +103,7 @@ fun VolumeSlider(
}
val value by valueState(state)
- Column(modifier) {
+ Column(modifier = modifier.animateContentSize(), verticalArrangement = Arrangement.Top) {
Row(
horizontalArrangement = Arrangement.spacedBy(12.dp),
modifier = Modifier.fillMaxWidth().height(40.dp),
@@ -127,7 +132,7 @@ fun VolumeSlider(
enabled = state.isEnabled,
modifier =
Modifier.height(40.dp)
- .padding(vertical = 8.dp)
+ .padding(top = 4.dp, bottom = 12.dp)
.sysuiResTag(state.label)
.clearAndSetSemantics {
if (state.isEnabled) {
@@ -168,6 +173,28 @@ fun VolumeSlider(
}
},
)
+ state.disabledMessage?.let { disabledMessage ->
+ AnimatedVisibility(visible = !state.isEnabled) {
+ Row(
+ modifier = Modifier.padding(bottom = 12.dp),
+ horizontalArrangement = Arrangement.spacedBy(8.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ MaterialIcon(
+ painter = painterResource(R.drawable.ic_error_outline),
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.onSurfaceVariant,
+ modifier = Modifier.size(16.dp),
+ )
+ Text(
+ text = disabledMessage,
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
+ style = MaterialTheme.typography.labelSmall,
+ modifier = Modifier.basicMarquee(),
+ )
+ }
+ }
+ }
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt
index 6349c1406a12..bc3013239289 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt
@@ -37,18 +37,17 @@ fun VolumePanelComposeScope.VerticalVolumePanelContent(
layout: ComponentsLayout,
modifier: Modifier = Modifier,
) {
- Column(
- modifier = modifier.verticalScroll(rememberScrollState()),
- verticalArrangement = Arrangement.spacedBy(20.dp),
- ) {
+ Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(20.dp)) {
for (component in layout.headerComponents) {
AnimatedVisibility(component.isVisible) {
with(component.component as ComposeVolumePanelUiComponent) { Content(Modifier) }
}
}
- for (component in layout.contentComponents) {
- AnimatedVisibility(component.isVisible) {
- with(component.component as ComposeVolumePanelUiComponent) { Content(Modifier) }
+ Column(Modifier.verticalScroll(rememberScrollState())) {
+ for (component in layout.contentComponents) {
+ AnimatedVisibility(component.isVisible) {
+ with(component.component as ComposeVolumePanelUiComponent) { Content(Modifier) }
+ }
}
}
diff --git a/packages/SystemUI/compose/scene/Android.bp b/packages/SystemUI/compose/scene/Android.bp
index 682c49cfd19c..090e9ccedda0 100644
--- a/packages/SystemUI/compose/scene/Android.bp
+++ b/packages/SystemUI/compose/scene/Android.bp
@@ -42,6 +42,7 @@ android_library {
"androidx.compose.material3_material3",
"PlatformComposeCore",
+ "mechanics",
],
kotlincflags: ["-Xjvm-default=all"],
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateOverlay.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateOverlay.kt
index 28116cb435e4..7d41a266adf2 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateOverlay.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateOverlay.kt
@@ -17,6 +17,7 @@
package com.android.compose.animation.scene
import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.mechanics.GestureContext
import kotlinx.coroutines.CoroutineScope
/** Trigger a one-off transition to show or hide an overlay. */
@@ -118,6 +119,7 @@ private class OneOffShowOrHideOverlayTransition(
override val isInitiatedByUserInput: Boolean = false
override val isUserInputOngoing: Boolean = false
+ override val gestureContext: GestureContext? = null
override suspend fun run() {
oneOffAnimation.run()
@@ -144,6 +146,7 @@ private class OneOffOverlayReplacingTransition(
override val isInitiatedByUserInput: Boolean = false
override val isUserInputOngoing: Boolean = false
+ override val gestureContext: GestureContext? = null
override suspend fun run() {
oneOffAnimation.run()
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
index 86be4a44f3cb..dad4e2491be0 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
@@ -17,6 +17,7 @@
package com.android.compose.animation.scene
import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.mechanics.GestureContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
@@ -193,6 +194,7 @@ private class OneOffSceneTransition(
get() = oneOffAnimation.progressVelocity
override val isUserInputOngoing: Boolean = false
+ override val gestureContext: GestureContext? = null
override suspend fun run() {
oneOffAnimation.run()
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index 2ca846424d93..916d85a80e77 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -16,62 +16,31 @@
package com.android.compose.animation.scene
+import androidx.compose.foundation.OverscrollEffect
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
+import androidx.compose.ui.input.pointer.PointerInputChange
+import androidx.compose.ui.input.pointer.PointerType
+import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.round
import androidx.compose.ui.util.fastCoerceIn
import com.android.compose.animation.scene.content.Content
import com.android.compose.animation.scene.content.state.TransitionState.Companion.DistanceUnspecified
-import com.android.compose.nestedscroll.OnStopScope
-import com.android.compose.nestedscroll.PriorityNestedScrollConnection
-import com.android.compose.nestedscroll.ScrollController
+import com.android.compose.animation.scene.effect.GestureEffect
+import com.android.compose.gesture.NestedDraggable
import com.android.compose.ui.util.SpaceVectorConverter
+import com.android.mechanics.DistanceGestureContext
+import com.android.mechanics.spec.InputDirection
import kotlin.math.absoluteValue
-import kotlinx.coroutines.CompletableDeferred
-import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-internal interface DraggableHandler {
- /**
- * Start a drag with the given [pointersDown] and [overSlop].
- *
- * The returned [DragController] should be used to continue or stop the drag.
- */
- fun onDragStarted(pointersDown: PointersInfo.PointersDown?, overSlop: Float): DragController
-}
-
-/**
- * The [DragController] provides control over the transition between two scenes through the [onDrag]
- * and [onStop] methods.
- */
-internal interface DragController {
- /**
- * Drag the current scene by [delta] pixels.
- *
- * @param delta The distance to drag the scene in pixels.
- * @return the consumed [delta]
- */
- fun onDrag(delta: Float): Float
-
- /**
- * Stop the current drag with the given [velocity].
- *
- * @param velocity The velocity of the drag when it stopped.
- * @return the consumed [velocity] when the animation complete
- */
- suspend fun onStop(velocity: Float): Float
-
- /** Cancels the current drag. */
- fun onCancel()
-}
-
-internal class DraggableHandlerImpl(
+internal class DraggableHandler(
internal val layoutImpl: SceneTransitionLayoutImpl,
internal val orientation: Orientation,
-) : DraggableHandler {
+ private val gestureEffectProvider: (ContentKey) -> GestureEffect,
+) : NestedDraggable {
/** The [DraggableHandler] can only have one active [DragController] at a time. */
private var dragController: DragControllerImpl? = null
@@ -92,20 +61,36 @@ internal class DraggableHandlerImpl(
internal val positionalThreshold
get() = with(layoutImpl.density) { 56.dp.toPx() }
+ /** The [OverscrollEffect] that should consume any overscroll on this draggable. */
+ internal val overscrollEffect: OverscrollEffect = DelegatingOverscrollEffect()
+
+ override fun shouldStartDrag(change: PointerInputChange): Boolean {
+ return layoutImpl.swipeDetector.detectSwipe(change)
+ }
+
+ override fun shouldConsumeNestedScroll(sign: Float): Boolean {
+ return this.enabled()
+ }
+
override fun onDragStarted(
- pointersDown: PointersInfo.PointersDown?,
- overSlop: Float,
- ): DragController {
- check(overSlop != 0f)
- val swipes = computeSwipes(pointersDown)
+ position: Offset,
+ sign: Float,
+ pointersDown: Int,
+ pointerType: PointerType?,
+ ): NestedDraggable.Controller {
+ check(sign != 0f)
+ val swipes = computeSwipes(position, pointersDown, pointerType)
val fromContent = layoutImpl.contentForUserActions()
swipes.updateSwipesResults(fromContent)
+ val upOrLeft = swipes.upOrLeftResult
+ val downOrRight = swipes.downOrRightResult
val result =
- (if (overSlop < 0f) swipes.upOrLeftResult else swipes.downOrRightResult)
- // As we were unable to locate a valid target scene, the initial SwipeAnimation
- // cannot be defined. Consequently, a simple NoOp Controller will be returned.
- ?: return NoOpDragController
+ when {
+ sign < 0 -> upOrLeft ?: downOrRight
+ sign >= 0f -> downOrRight ?: upOrLeft
+ else -> null
+ } ?: return NoOpDragController
val swipeAnimation = createSwipeAnimation(swipes, result)
return updateDragController(swipes, swipeAnimation)
@@ -131,7 +116,14 @@ internal class DraggableHandlerImpl(
else -> error("Unknown result $result ($upOrLeftResult $downOrRightResult)")
}
- return createSwipeAnimation(layoutImpl, result, isUpOrLeft, orientation)
+ val gestureContext =
+ DistanceGestureContext(
+ initialDragOffset = 0f,
+ initialDirection = if (isUpOrLeft) InputDirection.Min else InputDirection.Max,
+ directionChangeSlop = layoutImpl.directionChangeSlop,
+ )
+
+ return createSwipeAnimation(layoutImpl, result, isUpOrLeft, orientation, gestureContext)
}
private fun resolveSwipeSource(startedPosition: Offset): SwipeSource.Resolved? {
@@ -143,20 +135,109 @@ internal class DraggableHandlerImpl(
)
}
- private fun computeSwipes(pointersDown: PointersInfo.PointersDown?): Swipes {
- val fromSource = pointersDown?.let { resolveSwipeSource(it.startedPosition) }
+ private fun computeSwipes(
+ position: Offset,
+ pointersDown: Int,
+ pointerType: PointerType?,
+ ): Swipes {
+ val fromSource = resolveSwipeSource(position)
return Swipes(
- upOrLeft = resolveSwipe(orientation, isUpOrLeft = true, pointersDown, fromSource),
- downOrRight = resolveSwipe(orientation, isUpOrLeft = false, pointersDown, fromSource),
+ upOrLeft =
+ resolveSwipe(orientation, isUpOrLeft = true, fromSource, pointersDown, pointerType),
+ downOrRight =
+ resolveSwipe(orientation, isUpOrLeft = false, fromSource, pointersDown, pointerType),
)
}
+
+ /**
+ * An implementation of [OverscrollEffect] that delegates to the correct content effect
+ * depending on the current scene/overlays and transition.
+ */
+ private inner class DelegatingOverscrollEffect :
+ OverscrollEffect, SpaceVectorConverter by SpaceVectorConverter(orientation) {
+ private var currentContent: ContentKey? = null
+ private var currentDelegate: GestureEffect? = null
+ set(value) {
+ field?.let { delegate ->
+ if (delegate.isInProgress) {
+ layoutImpl.animationScope.launch { delegate.ensureApplyToFlingIsCalled() }
+ }
+ }
+
+ field = value
+ }
+
+ override val isInProgress: Boolean
+ get() = currentDelegate?.isInProgress ?: false
+
+ override fun applyToScroll(
+ delta: Offset,
+ source: NestedScrollSource,
+ performScroll: (Offset) -> Offset,
+ ): Offset {
+ val available = delta.toFloat()
+ if (available == 0f) {
+ return performScroll(delta)
+ }
+
+ ensureDelegateIsNotNull(available)
+ val delegate = checkNotNull(currentDelegate)
+ return if (delegate.node.node.isAttached) {
+ delegate.applyToScroll(delta, source, performScroll)
+ } else {
+ performScroll(delta)
+ }
+ }
+
+ override suspend fun applyToFling(
+ velocity: Velocity,
+ performFling: suspend (Velocity) -> Velocity,
+ ) {
+ val available = velocity.toFloat()
+ if (available != 0f && isDrivingTransition) {
+ ensureDelegateIsNotNull(available)
+ }
+
+ // Note: we set currentDelegate and currentContent to null before calling performFling,
+ // which can suspend and take a lot of time.
+ val delegate = currentDelegate
+ currentDelegate = null
+ currentContent = null
+
+ if (delegate != null && delegate.node.node.isAttached) {
+ delegate.applyToFling(velocity, performFling)
+ } else {
+ performFling(velocity)
+ }
+ }
+
+ private fun ensureDelegateIsNotNull(direction: Float) {
+ require(direction != 0f)
+ if (isInProgress) {
+ return
+ }
+
+ val content =
+ if (isDrivingTransition) {
+ checkNotNull(dragController).swipeAnimation.contentByDirection(direction)
+ } else {
+ layoutImpl.contentForUserActions().key
+ }
+
+ if (content != currentContent) {
+ currentContent = content
+ currentDelegate = gestureEffectProvider(content)
+ }
+ }
+ }
}
private fun resolveSwipe(
orientation: Orientation,
isUpOrLeft: Boolean,
- pointersDown: PointersInfo.PointersDown?,
fromSource: SwipeSource.Resolved?,
+ pointersDown: Int,
+ pointerType: PointerType?,
): Swipe.Resolved {
return Swipe.Resolved(
direction =
@@ -175,28 +256,22 @@ private fun resolveSwipe(
SwipeDirection.Resolved.Down
}
},
- // If the number of pointers is not specified, 1 is assumed.
- pointerCount = pointersDown?.count ?: 1,
- // Resolves the pointer type only if all pointers are of the same type.
- pointersType = pointersDown?.countByType?.keys?.singleOrNull(),
+ pointerCount = pointersDown,
+ pointerType = pointerType,
fromSource = fromSource,
)
}
/** @param swipes The [Swipes] associated to the current gesture. */
private class DragControllerImpl(
- private val draggableHandler: DraggableHandlerImpl,
+ private val draggableHandler: DraggableHandler,
val swipes: Swipes,
var swipeAnimation: SwipeAnimation<*>,
-) : DragController, SpaceVectorConverter by SpaceVectorConverter(draggableHandler.orientation) {
+) :
+ NestedDraggable.Controller,
+ SpaceVectorConverter by SpaceVectorConverter(draggableHandler.orientation) {
val layoutState = draggableHandler.layoutImpl.state
- val overscrollableContent: OverscrollableContent =
- when (draggableHandler.orientation) {
- Orientation.Vertical -> draggableHandler.layoutImpl.verticalOverscrollableContent
- Orientation.Horizontal -> draggableHandler.layoutImpl.horizontalOverscrollableContent
- }
-
/**
* Whether this handle is active. If this returns false, calling [onDrag] and [onStop] will do
* nothing.
@@ -231,57 +306,26 @@ private class DragControllerImpl(
if (delta == 0f || !isDrivingTransition || initialAnimation.isAnimatingOffset()) {
return 0f
}
+
// swipeAnimation can change during the gesture, we want to always use the initial reference
// during the whole drag gesture.
- return dragWithOverscroll(delta, animation = initialAnimation)
- }
-
- private fun <T : ContentKey> dragWithOverscroll(
- delta: Float,
- animation: SwipeAnimation<T>,
- ): Float {
- require(delta != 0f) { "delta should not be 0" }
- var overscrollEffect = overscrollableContent.currentOverscrollEffect
-
- // If we're already overscrolling, continue with the current effect for a smooth finish.
- if (overscrollEffect == null || !overscrollEffect.isInProgress) {
- // Otherwise, determine the target content (toContent or fromContent) for the new
- // overscroll effect based on the gesture's direction.
- val content = animation.contentByDirection(delta)
- overscrollEffect = overscrollableContent.applyOverscrollEffectOn(content)
- }
-
- // TODO(b/378470603) Remove this check once NestedDraggable is used to handle drags.
- if (!overscrollEffect.node.node.isAttached) {
- return drag(delta, animation)
- }
-
- return overscrollEffect
- .applyToScroll(
- delta = delta.toOffset(),
- source = NestedScrollSource.UserInput,
- performScroll = {
- val preScrollAvailable = it.toFloat()
- drag(preScrollAvailable, animation).toOffset()
- },
- )
- .toFloat()
+ return drag(delta, animation = initialAnimation)
}
private fun <T : ContentKey> drag(delta: Float, animation: SwipeAnimation<T>): Float {
- if (delta == 0f) return 0f
-
val distance = animation.distance()
val previousOffset = animation.dragOffset
val desiredOffset = previousOffset + delta
- val desiredProgress = animation.computeProgress(desiredOffset)
// Note: the distance could be negative if fromContent is above or to the left of toContent.
val newOffset =
when {
- distance == DistanceUnspecified ||
- animation.contentTransition.isWithinProgressRange(desiredProgress) ->
- desiredOffset
+ distance == DistanceUnspecified -> {
+ // Consume everything so that we don't overscroll, this will be coerced later
+ // when the distance is defined.
+ delta
+ }
+
distance > 0f -> desiredOffset.fastCoerceIn(0f, distance)
else -> desiredOffset.fastCoerceIn(distance, 0f)
}
@@ -290,12 +334,8 @@ private class DragControllerImpl(
return newOffset - previousOffset
}
- override suspend fun onStop(velocity: Float): Float {
- // To ensure that any ongoing animation completes gracefully and avoids an undefined state,
- // we execute the actual `onStop` logic in a non-cancellable context. This prevents the
- // coroutine from being cancelled prematurely, which could interrupt the animation.
- // TODO(b/378470603) Remove this check once NestedDraggable is used to handle drags.
- return withContext(NonCancellable) { onStop(velocity, swipeAnimation) }
+ override suspend fun onDragStopped(velocity: Float, awaitFling: suspend () -> Unit): Float {
+ return onStop(velocity, swipeAnimation, awaitFling)
}
private suspend fun <T : ContentKey> onStop(
@@ -306,6 +346,7 @@ private class DragControllerImpl(
// callbacks (like onAnimationCompleted()) might incorrectly finish a new transition that
// replaced this one.
swipeAnimation: SwipeAnimation<T>,
+ awaitFling: suspend () -> Unit,
): Float {
// The state was changed since the drag started; don't do anything.
if (!isDrivingTransition || swipeAnimation.isAnimatingOffset()) {
@@ -337,33 +378,7 @@ private class DragControllerImpl(
fromContent
}
- val overscrollEffect = overscrollableContent.applyOverscrollEffectOn(targetContent)
-
- // TODO(b/378470603) Remove this check once NestedDraggable is used to handle drags.
- if (!overscrollEffect.node.node.isAttached) {
- return swipeAnimation.animateOffset(velocity, targetContent)
- }
-
- val overscrollCompletable = CompletableDeferred<Unit>()
- try {
- overscrollEffect.applyToFling(
- velocity = velocity.toVelocity(),
- performFling = {
- val velocityLeft = it.toFloat()
- swipeAnimation
- .animateOffset(
- velocityLeft,
- targetContent,
- overscrollCompletable = overscrollCompletable,
- )
- .toVelocity()
- },
- )
- } finally {
- overscrollCompletable.complete(Unit)
- }
-
- return velocity
+ return swipeAnimation.animateOffset(velocity, targetContent, awaitFling = awaitFling)
}
/**
@@ -408,10 +423,6 @@ private class DragControllerImpl(
isCloserToTarget()
}
}
-
- override fun onCancel() {
- swipeAnimation.contentTransition.coroutineScope.launch { onStop(velocity = 0f) }
- }
}
/** The [Swipe] associated to a given fromScene, startedPosition and pointersDown. */
@@ -453,15 +464,15 @@ internal class Swipes(val upOrLeft: Swipe.Resolved, val downOrRight: Swipe.Resol
(actionSwipe.fromSource != null &&
actionSwipe.fromSource != swipe.fromSource) ||
// The action requires a specific pointerType.
- (actionSwipe.pointersType != null &&
- actionSwipe.pointersType != swipe.pointersType)
+ (actionSwipe.pointerType != null &&
+ actionSwipe.pointerType != swipe.pointerType)
) {
// This action is not eligible.
return@forEach
}
val sameFromSource = actionSwipe.fromSource == swipe.fromSource
- val samePointerType = actionSwipe.pointersType == swipe.pointersType
+ val samePointerType = actionSwipe.pointerType == swipe.pointerType
// Prioritize actions with a perfect match.
if (sameFromSource && samePointerType) {
return actionResult
@@ -496,82 +507,6 @@ internal class Swipes(val upOrLeft: Swipe.Resolved, val downOrRight: Swipe.Resol
}
}
-internal class NestedScrollHandlerImpl(
- private val draggableHandler: DraggableHandlerImpl,
- private val pointersInfoOwner: PointersInfoOwner,
-) {
- val connection: PriorityNestedScrollConnection = nestedScrollConnection()
-
- private fun nestedScrollConnection(): PriorityNestedScrollConnection {
- var lastPointersDown: PointersInfo.PointersDown? = null
-
- return PriorityNestedScrollConnection(
- orientation = draggableHandler.orientation,
- canStartPreScroll = { _, _, _ -> false },
- canStartPostScroll = { offsetAvailable, _, _ ->
- if (offsetAvailable == 0f) return@PriorityNestedScrollConnection false
-
- lastPointersDown =
- when (val info = pointersInfoOwner.pointersInfo()) {
- PointersInfo.MouseWheel -> {
- // Do not support mouse wheel interactions
- return@PriorityNestedScrollConnection false
- }
-
- is PointersInfo.PointersDown -> info
- null -> null
- }
-
- draggableHandler.layoutImpl
- .contentForUserActions()
- .shouldEnableSwipes(draggableHandler.orientation)
- },
- onStart = { firstScroll ->
- scrollController(
- dragController =
- draggableHandler.onDragStarted(
- pointersDown = lastPointersDown,
- overSlop = firstScroll,
- ),
- pointersInfoOwner = pointersInfoOwner,
- )
- },
- )
- }
-}
-
-private fun scrollController(
- dragController: DragController,
- pointersInfoOwner: PointersInfoOwner,
-): ScrollController {
- return object : ScrollController {
- override fun onScroll(deltaScroll: Float, source: NestedScrollSource): Float {
- if (pointersInfoOwner.pointersInfo() == PointersInfo.MouseWheel) {
- // Do not support mouse wheel interactions
- return 0f
- }
-
- return dragController.onDrag(delta = deltaScroll)
- }
-
- override suspend fun OnStopScope.onStop(initialVelocity: Float): Float {
- return dragController.onStop(velocity = initialVelocity)
- }
-
- override fun onCancel() {
- dragController.onCancel()
- }
-
- /**
- * We need to maintain scroll priority even if the scene transition can no longer consume
- * the scroll gesture to allow us to return to the previous scene.
- */
- override fun canCancelScroll(available: Float, consumed: Float) = false
-
- override fun canStopOnPreFling() = true
- }
-}
-
/**
* The number of pixels below which there won't be a visible difference in the transition and from
* which the animation can stop.
@@ -580,12 +515,8 @@ private fun scrollController(
// account instead.
internal const val OffsetVisibilityThreshold = 0.5f
-private object NoOpDragController : DragController {
+private object NoOpDragController : NestedDraggable.Controller {
override fun onDrag(delta: Float) = 0f
- override suspend fun onStop(velocity: Float) = 0f
-
- override fun onCancel() {
- /* do nothing */
- }
+ override suspend fun onDragStopped(velocity: Float, awaitFling: suspend () -> Unit): Float = 0f
}
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
deleted file mode 100644
index 89320f1303e5..000000000000
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
+++ /dev/null
@@ -1,678 +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.annotation.VisibleForTesting
-import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.foundation.gestures.awaitHorizontalTouchSlopOrCancellation
-import androidx.compose.foundation.gestures.awaitVerticalTouchSlopOrCancellation
-import androidx.compose.runtime.Stable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
-import androidx.compose.ui.input.nestedscroll.NestedScrollDispatcher
-import androidx.compose.ui.input.nestedscroll.NestedScrollSource
-import androidx.compose.ui.input.pointer.AwaitPointerEventScope
-import androidx.compose.ui.input.pointer.PointerEvent
-import androidx.compose.ui.input.pointer.PointerEventPass
-import androidx.compose.ui.input.pointer.PointerEventType
-import androidx.compose.ui.input.pointer.PointerId
-import androidx.compose.ui.input.pointer.PointerInputChange
-import androidx.compose.ui.input.pointer.PointerInputScope
-import androidx.compose.ui.input.pointer.PointerType
-import androidx.compose.ui.input.pointer.SuspendingPointerInputModifierNode
-import androidx.compose.ui.input.pointer.changedToDown
-import androidx.compose.ui.input.pointer.changedToUpIgnoreConsumed
-import androidx.compose.ui.input.pointer.positionChange
-import androidx.compose.ui.input.pointer.positionChangeIgnoreConsumed
-import androidx.compose.ui.input.pointer.util.VelocityTracker
-import androidx.compose.ui.input.pointer.util.addPointerInputChange
-import androidx.compose.ui.node.CompositionLocalConsumerModifierNode
-import androidx.compose.ui.node.DelegatingNode
-import androidx.compose.ui.node.ModifierNodeElement
-import androidx.compose.ui.node.PointerInputModifierNode
-import androidx.compose.ui.node.currentValueOf
-import androidx.compose.ui.platform.LocalViewConfiguration
-import androidx.compose.ui.unit.IntSize
-import androidx.compose.ui.unit.Velocity
-import androidx.compose.ui.util.fastAll
-import androidx.compose.ui.util.fastAny
-import androidx.compose.ui.util.fastFilter
-import androidx.compose.ui.util.fastFirstOrNull
-import androidx.compose.ui.util.fastForEach
-import androidx.compose.ui.util.fastSumBy
-import com.android.compose.ui.util.SpaceVectorConverter
-import kotlin.coroutines.cancellation.CancellationException
-import kotlin.math.sign
-import kotlinx.coroutines.currentCoroutineContext
-import kotlinx.coroutines.isActive
-import kotlinx.coroutines.launch
-
-/**
- * Make an element draggable in the given [orientation].
- *
- * The main difference with [multiPointerDraggable] and
- * [androidx.compose.foundation.gestures.draggable] is that [onDragStarted] also receives the number
- * of pointers that are down when the drag is started. If you don't need this information, you
- * should use `draggable` instead.
- *
- * Note that the current implementation is trivial: we wait for the touch slope on the *first* down
- * pointer, then we count the number of distinct pointers that are down right before calling
- * [onDragStarted]. This means that the drag won't start when a first pointer is down (but not
- * dragged) and a second pointer is down and dragged. This is an implementation detail that might
- * change in the future.
- */
-@VisibleForTesting
-@Stable
-internal fun Modifier.multiPointerDraggable(
- orientation: Orientation,
- onDragStarted: (pointersDown: PointersInfo.PointersDown, overSlop: Float) -> DragController,
- onFirstPointerDown: () -> Unit = {},
- swipeDetector: SwipeDetector = DefaultSwipeDetector,
- dispatcher: NestedScrollDispatcher,
-): Modifier =
- this.then(
- MultiPointerDraggableElement(
- orientation,
- onDragStarted,
- onFirstPointerDown,
- swipeDetector,
- dispatcher,
- )
- )
-
-private data class MultiPointerDraggableElement(
- private val orientation: Orientation,
- private val onDragStarted:
- (pointersDown: PointersInfo.PointersDown, overSlop: Float) -> DragController,
- private val onFirstPointerDown: () -> Unit,
- private val swipeDetector: SwipeDetector,
- private val dispatcher: NestedScrollDispatcher,
-) : ModifierNodeElement<MultiPointerDraggableNode>() {
- override fun create(): MultiPointerDraggableNode =
- MultiPointerDraggableNode(
- orientation = orientation,
- onDragStarted = onDragStarted,
- onFirstPointerDown = onFirstPointerDown,
- swipeDetector = swipeDetector,
- dispatcher = dispatcher,
- )
-
- override fun update(node: MultiPointerDraggableNode) {
- node.orientation = orientation
- node.onDragStarted = onDragStarted
- node.onFirstPointerDown = onFirstPointerDown
- node.swipeDetector = swipeDetector
- }
-}
-
-internal class MultiPointerDraggableNode(
- orientation: Orientation,
- var onDragStarted: (pointersDown: PointersInfo.PointersDown, overSlop: Float) -> DragController,
- var onFirstPointerDown: () -> Unit,
- swipeDetector: SwipeDetector = DefaultSwipeDetector,
- private val dispatcher: NestedScrollDispatcher,
-) : DelegatingNode(), PointerInputModifierNode, CompositionLocalConsumerModifierNode {
- private val pointerTracker = delegate(SuspendingPointerInputModifierNode { pointerTracker() })
- private val pointerInput = delegate(SuspendingPointerInputModifierNode { pointerInput() })
- private val velocityTracker = VelocityTracker()
-
- var swipeDetector: SwipeDetector = swipeDetector
- set(value) {
- if (value != field) {
- field = value
- pointerInput.resetPointerInputHandler()
- }
- }
-
- private var converter = SpaceVectorConverter(orientation)
-
- fun Offset.toFloat(): Float = with(converter) { this@toFloat.toFloat() }
-
- fun Velocity.toFloat(): Float = with(converter) { this@toFloat.toFloat() }
-
- fun Float.toOffset(): Offset = with(converter) { this@toOffset.toOffset() }
-
- fun Float.toVelocity(): Velocity = with(converter) { this@toVelocity.toVelocity() }
-
- var orientation: Orientation = orientation
- set(value) {
- // Reset the pointer input whenever orientation changed.
- if (value != field) {
- field = value
- converter = SpaceVectorConverter(value)
- pointerInput.resetPointerInputHandler()
- }
- }
-
- override fun onCancelPointerInput() {
- pointerTracker.onCancelPointerInput()
- pointerInput.onCancelPointerInput()
- }
-
- override fun onPointerEvent(
- pointerEvent: PointerEvent,
- pass: PointerEventPass,
- bounds: IntSize,
- ) {
- // The order is important here: the tracker is always called first.
- pointerTracker.onPointerEvent(pointerEvent, pass, bounds)
- pointerInput.onPointerEvent(pointerEvent, pass, bounds)
- }
-
- private var lastPointerEvent: PointerEvent? = null
- private var startedPosition: Offset? = null
- private var countPointersDown: Int = 0
-
- internal fun pointersInfo(): PointersInfo? {
- // This may be null, i.e. when the user uses TalkBack
- val lastPointerEvent = lastPointerEvent ?: return null
-
- if (lastPointerEvent.type == PointerEventType.Scroll) return PointersInfo.MouseWheel
-
- val startedPosition = startedPosition ?: return null
-
- return PointersInfo.PointersDown(
- startedPosition = startedPosition,
- count = countPointersDown,
- countByType =
- buildMap {
- lastPointerEvent.changes.fastForEach { change ->
- if (!change.pressed) return@fastForEach
- val newValue = (get(change.type) ?: 0) + 1
- put(change.type, newValue)
- }
- },
- )
- }
-
- private suspend fun PointerInputScope.pointerTracker() {
- val currentContext = currentCoroutineContext()
- awaitPointerEventScope {
- var velocityPointerId: PointerId? = null
- // Intercepts pointer inputs and exposes [PointersInfo], via
- // [requireAncestorPointersInfoOwner], to our descendants.
- while (currentContext.isActive) {
- // During the Initial pass, we receive the event after our ancestors.
- val pointerEvent = awaitPointerEvent(PointerEventPass.Initial)
-
- // Ignore cursor has entered the input region.
- // This will only be sent after the cursor is hovering when in the input region.
- if (pointerEvent.type == PointerEventType.Enter) continue
-
- val changes = pointerEvent.changes
- lastPointerEvent = pointerEvent
- countPointersDown = changes.countDown()
-
- when {
- // There are no more pointers down.
- countPointersDown == 0 -> {
- startedPosition = null
-
- // In case of multiple events with 0 pointers down (not pressed) we may have
- // already removed the velocityPointer
- val lastPointerUp = changes.fastFilter { it.id == velocityPointerId }
- check(lastPointerUp.isEmpty() || lastPointerUp.size == 1) {
- "There are ${lastPointerUp.size} pointers up: $lastPointerUp"
- }
- if (lastPointerUp.size == 1) {
- velocityTracker.addPointerInputChange(lastPointerUp.first())
- }
- }
-
- // The first pointer down, startedPosition was not set.
- startedPosition == null -> {
- // Mouse wheel could start with multiple pointer down
- val firstPointerDown = changes.first()
- velocityPointerId = firstPointerDown.id
- velocityTracker.resetTracking()
- velocityTracker.addPointerInputChange(firstPointerDown)
- startedPosition = firstPointerDown.position
- onFirstPointerDown()
- }
-
- // Changes with at least one pointer
- else -> {
- val pointerChange = changes.first()
-
- // Assuming that the list of changes doesn't have two changes with the same
- // id (PointerId), we can check:
- // - If the first change has `id` equals to `velocityPointerId` (this should
- // always be true unless the pointer has been removed).
- // - If it does, we've found our change event (assuming there aren't any
- // others changes with the same id in this PointerEvent - not checked).
- // - If it doesn't, we can check that the change with that id isn't in first
- // place (which should never happen - this will crash).
- check(
- pointerChange.id == velocityPointerId ||
- !changes.fastAny { it.id == velocityPointerId }
- ) {
- "$velocityPointerId is present, but not the first: $changes"
- }
-
- // If the previous pointer has been removed, we use the first available
- // change to keep tracking the velocity.
- velocityPointerId =
- if (pointerChange.pressed) {
- pointerChange.id
- } else {
- changes.first { it.pressed }.id
- }
-
- velocityTracker.addPointerInputChange(pointerChange)
- }
- }
- }
- }
- }
-
- private suspend fun PointerInputScope.pointerInput() {
- val currentContext = currentCoroutineContext()
- awaitPointerEventScope {
- while (currentContext.isActive) {
- try {
- detectDragGestures(
- orientation = orientation,
- onDragStart = { pointersDown, overSlop ->
- onDragStarted(pointersDown, overSlop)
- },
- onDrag = { controller, amount ->
- dispatchScrollEvents(
- availableOnPreScroll = amount,
- onScroll = { controller.onDrag(it) },
- source = NestedScrollSource.UserInput,
- )
- },
- onDragEnd = { controller ->
- startFlingGesture(
- initialVelocity =
- currentValueOf(LocalViewConfiguration)
- .maximumFlingVelocity
- .let {
- val maxVelocity = Velocity(it, it)
- velocityTracker.calculateVelocity(maxVelocity)
- }
- .toFloat(),
- onFling = { controller.onStop(it) },
- )
- },
- onDragCancel = { controller ->
- startFlingGesture(
- initialVelocity = 0f,
- onFling = { controller.onStop(it) },
- )
- },
- swipeDetector = swipeDetector,
- )
- } catch (exception: CancellationException) {
- // If the coroutine scope is active, we can just restart the drag cycle.
- if (!currentContext.isActive) {
- throw exception
- }
- }
- }
- }
- }
-
- /**
- * Start a fling gesture in another CoroutineScope, this is to ensure that even when the pointer
- * input scope is reset we will continue any coroutine scope that we started from these methods
- * while the pointer input scope was active.
- *
- * Note: Inspired by [androidx.compose.foundation.gestures.ScrollableNode.onDragStopped]
- */
- private fun startFlingGesture(
- initialVelocity: Float,
- onFling: suspend (velocity: Float) -> Float,
- ) {
- // Note: [AwaitPointerEventScope] is annotated as @RestrictsSuspension, we need another
- // CoroutineScope to run the fling gestures.
- // We do not need to cancel this [Job], the source will take care of emitting an
- // [onPostFling] before starting a new gesture.
- dispatcher.coroutineScope.launch {
- dispatchFlingEvents(availableOnPreFling = initialVelocity, onFling = onFling)
- }
- }
-
- /**
- * Use the nested scroll system to fire scroll events. This allows us to consume events from our
- * ancestors during the pre-scroll and post-scroll phases.
- *
- * @param availableOnPreScroll amount available before the scroll, this can be partially
- * consumed by our ancestors.
- * @param onScroll function that returns the amount consumed during a scroll given the amount
- * available after the [NestedScrollConnection.onPreScroll].
- * @param source the source of the scroll event
- * @return Total offset consumed.
- */
- private inline fun dispatchScrollEvents(
- availableOnPreScroll: Float,
- onScroll: (delta: Float) -> Float,
- source: NestedScrollSource,
- ): Float {
- // PreScroll phase
- val consumedByPreScroll =
- dispatcher
- .dispatchPreScroll(available = availableOnPreScroll.toOffset(), source = source)
- .toFloat()
-
- // Scroll phase
- val availableOnScroll = availableOnPreScroll - consumedByPreScroll
- val consumedBySelfScroll = onScroll(availableOnScroll)
-
- // PostScroll phase
- val availableOnPostScroll = availableOnScroll - consumedBySelfScroll
- val consumedByPostScroll =
- dispatcher
- .dispatchPostScroll(
- consumed = consumedBySelfScroll.toOffset(),
- available = availableOnPostScroll.toOffset(),
- source = source,
- )
- .toFloat()
-
- return consumedByPreScroll + consumedBySelfScroll + consumedByPostScroll
- }
-
- /**
- * Use the nested scroll system to fire fling events. This allows us to consume events from our
- * ancestors during the pre-fling and post-fling phases.
- *
- * @param availableOnPreFling velocity available before the fling, this can be partially
- * consumed by our ancestors.
- * @param onFling function that returns the velocity consumed during the fling given the
- * velocity available after the [NestedScrollConnection.onPreFling].
- * @return Total velocity consumed.
- */
- private suspend inline fun dispatchFlingEvents(
- availableOnPreFling: Float,
- onFling: suspend (velocity: Float) -> Float,
- ): Float {
- // PreFling phase
- val consumedByPreFling =
- dispatcher.dispatchPreFling(available = availableOnPreFling.toVelocity()).toFloat()
-
- // Fling phase
- val availableOnFling = availableOnPreFling - consumedByPreFling
- val consumedBySelfFling = onFling(availableOnFling)
-
- // PostFling phase
- val availableOnPostFling = availableOnFling - consumedBySelfFling
- val consumedByPostFling =
- dispatcher
- .dispatchPostFling(
- consumed = consumedBySelfFling.toVelocity(),
- available = availableOnPostFling.toVelocity(),
- )
- .toFloat()
-
- return consumedByPreFling + consumedBySelfFling + consumedByPostFling
- }
-
- /**
- * Detect drag gestures in the given [orientation].
- *
- * This function is a mix of [androidx.compose.foundation.gestures.awaitDownAndSlop] and
- * [androidx.compose.foundation.gestures.detectVerticalDragGestures] to add support for passing
- * the number of pointers down to [onDragStart].
- */
- private suspend fun AwaitPointerEventScope.detectDragGestures(
- orientation: Orientation,
- onDragStart: (pointersDown: PointersInfo.PointersDown, overSlop: Float) -> DragController,
- onDrag: (controller: DragController, dragAmount: Float) -> Unit,
- onDragEnd: (controller: DragController) -> Unit,
- onDragCancel: (controller: DragController) -> Unit,
- swipeDetector: SwipeDetector,
- ) {
- val consumablePointer =
- awaitConsumableEvent {
- // We are searching for an event that can be used as the starting point for the
- // drag gesture. Our options are:
- // - Initial: These events should never be consumed by the MultiPointerDraggable
- // since our ancestors can consume the gesture, but we would eliminate this
- // possibility for our descendants.
- // - Main: These events are consumed during the drag gesture, and they are a
- // good place to start if the previous event has not been consumed.
- // - Final: If the previous event has been consumed, we can wait for the Main
- // pass to finish. If none of our ancestors were interested in the event, we
- // can wait for an unconsumed event in the Final pass.
- val previousConsumed = currentEvent.changes.fastAny { it.isConsumed }
- if (previousConsumed) PointerEventPass.Final else PointerEventPass.Main
- }
- .changes
- .first()
-
- var overSlop = 0f
- val onSlopReached = { change: PointerInputChange, over: Float ->
- if (swipeDetector.detectSwipe(change)) {
- change.consume()
- overSlop = over
- }
- }
-
- // TODO(b/291055080): Replace by await[Orientation]PointerSlopOrCancellation once it
- // is public.
- val drag =
- when (orientation) {
- Orientation.Horizontal ->
- awaitHorizontalTouchSlopOrCancellation(consumablePointer.id, onSlopReached)
- Orientation.Vertical ->
- awaitVerticalTouchSlopOrCancellation(consumablePointer.id, onSlopReached)
- } ?: return
-
- val lastPointersDown =
- checkNotNull(pointersInfo()) {
- "We should have pointers down, last event: $currentEvent"
- }
- as PointersInfo.PointersDown
- // Make sure that overSlop is not 0f. This can happen when the user drags by exactly
- // the touch slop. However, the overSlop we pass to onDragStarted() is used to
- // compute the direction we are dragging in, so overSlop should never be 0f.
- if (overSlop == 0f) {
- // If the user drags in the opposite direction, the delta becomes zero because
- // we return to the original point. Therefore, we should use the previous event
- // to calculate the direction.
- val delta = (drag.position - drag.previousPosition).toFloat()
- check(delta != 0f) {
- buildString {
- append("delta is equal to 0 ")
- append("touchSlop ${currentValueOf(LocalViewConfiguration).touchSlop} ")
- append("consumablePointer.position ${consumablePointer.position} ")
- append("drag.position ${drag.position} ")
- append("drag.previousPosition ${drag.previousPosition}")
- }
- }
- overSlop = delta.sign
- }
-
- val controller = onDragStart(lastPointersDown, overSlop)
- val successful: Boolean
- try {
- onDrag(controller, overSlop)
-
- successful =
- drag(
- initialPointerId = drag.id,
- hasDragged = { it.positionChangeIgnoreConsumed().toFloat() != 0f },
- onDrag = {
- onDrag(controller, it.positionChange().toFloat())
- it.consume()
- },
- onIgnoredEvent = {
- // We are still dragging an object, but this event is not of interest to the
- // caller.
- // This event will not trigger the onDrag event, but we will consume the
- // event to prevent another pointerInput from interrupting the current
- // gesture just because the event was ignored.
- it.consume()
- },
- )
- } catch (t: Throwable) {
- onDragCancel(controller)
- throw t
- }
-
- if (successful) {
- onDragEnd(controller)
- } else {
- onDragCancel(controller)
- }
- }
-
- private suspend fun AwaitPointerEventScope.awaitConsumableEvent(
- pass: () -> PointerEventPass
- ): PointerEvent {
- fun canBeConsumed(changes: List<PointerInputChange>): Boolean {
- // At least one pointer down AND
- return changes.fastAny { it.pressed } &&
- // All pointers must be either:
- changes.fastAll {
- // A) unconsumed AND recently pressed
- it.changedToDown() ||
- // B) unconsumed AND in a new position (on the current axis)
- it.positionChange().toFloat() != 0f
- }
- }
-
- var event: PointerEvent
- do {
- event = awaitPointerEvent(pass = pass())
- } while (!canBeConsumed(event.changes))
-
- // We found a consumable event in the Main pass
- return event
- }
-
- /**
- * Continues to read drag events until all pointers are up or the drag event is canceled. The
- * initial pointer to use for driving the drag is [initialPointerId]. [hasDragged] passes the
- * result whether a change was detected from the drag function or not.
- *
- * Whenever the pointer moves, if [hasDragged] returns true, [onDrag] is called; otherwise,
- * [onIgnoredEvent] is called.
- *
- * @return true when gesture ended with all pointers up and false when the gesture was canceled.
- *
- * Note: Inspired by DragGestureDetector.kt
- */
- private suspend inline fun AwaitPointerEventScope.drag(
- initialPointerId: PointerId,
- hasDragged: (PointerInputChange) -> Boolean,
- onDrag: (PointerInputChange) -> Unit,
- onIgnoredEvent: (PointerInputChange) -> Unit,
- ): Boolean {
- val pointer = currentEvent.changes.fastFirstOrNull { it.id == initialPointerId }
- val isPointerUp = pointer?.pressed != true
- if (isPointerUp) {
- return false // The pointer has already been lifted, so the gesture is canceled
- }
- var pointerId = initialPointerId
- while (true) {
- val change = awaitDragOrUp(pointerId, hasDragged, onIgnoredEvent) ?: return false
-
- if (change.isConsumed) {
- return false
- }
-
- if (change.changedToUpIgnoreConsumed()) {
- return true
- }
-
- onDrag(change)
- pointerId = change.id
- }
- }
-
- /**
- * Waits for a single drag in one axis, final pointer up, or all pointers are up. When
- * [initialPointerId] has lifted, another pointer that is down is chosen to be the finger
- * governing the drag. When the final pointer is lifted, that [PointerInputChange] is returned.
- * When a drag is detected, that [PointerInputChange] is returned. A drag is only detected when
- * [hasDragged] returns `true`. Events that should not be captured are passed to
- * [onIgnoredEvent].
- *
- * `null` is returned if there was an error in the pointer input stream and the pointer that was
- * down was dropped before the 'up' was received.
- *
- * Note: Inspired by DragGestureDetector.kt
- */
- private suspend inline fun AwaitPointerEventScope.awaitDragOrUp(
- initialPointerId: PointerId,
- hasDragged: (PointerInputChange) -> Boolean,
- onIgnoredEvent: (PointerInputChange) -> Unit,
- ): PointerInputChange? {
- var pointerId = initialPointerId
- while (true) {
- val event = awaitPointerEvent()
- val dragEvent = event.changes.fastFirstOrNull { it.id == pointerId } ?: return null
- if (dragEvent.changedToUpIgnoreConsumed()) {
- val otherDown = event.changes.fastFirstOrNull { it.pressed }
- if (otherDown == null) {
- // This is the last "up"
- return dragEvent
- } else {
- pointerId = otherDown.id
- }
- } else if (hasDragged(dragEvent)) {
- return dragEvent
- } else {
- onIgnoredEvent(dragEvent)
- }
- }
- }
-
- private fun List<PointerInputChange>.countDown() = fastSumBy { if (it.pressed) 1 else 0 }
-}
-
-internal fun interface PointersInfoOwner {
- /**
- * Provides information about the pointers interacting with this composable.
- *
- * @return A [PointersInfo] object containing details about the pointers, including the starting
- * position and the number of pointers down, or `null` if there are no pointers down.
- */
- fun pointersInfo(): PointersInfo?
-}
-
-internal sealed interface PointersInfo {
- /**
- * Holds information about pointer interactions within a composable.
- *
- * This class stores details such as the starting position of a gesture, the number of pointers
- * down, and whether the last pointer event was a mouse wheel scroll.
- *
- * @param startedPosition The starting position of the gesture. This is the position where the
- * first pointer touched the screen, not necessarily the point where dragging begins. This may
- * be different from the initial touch position if a child composable intercepts the gesture
- * before this one.
- * @param count The number of pointers currently down.
- * @param countByType Provide a map of pointer types to the count of pointers of that type
- * currently down/pressed.
- */
- data class PointersDown(
- val startedPosition: Offset,
- val count: Int,
- val countByType: Map<PointerType, Int>,
- ) : PointersInfo {
- init {
- check(count > 0) { "We should have at least 1 pointer down, $count instead" }
- }
- }
-
- /** Indicates whether the last pointer event was a mouse wheel scroll. */
- data object MouseWheel : PointersInfo
-}
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 8a6a0d6dbb99..621166e1823a 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
@@ -26,6 +26,8 @@ import com.android.compose.animation.scene.UserActionResult.HideOverlay
import com.android.compose.animation.scene.UserActionResult.ReplaceByOverlay
import com.android.compose.animation.scene.UserActionResult.ShowOverlay
import com.android.compose.animation.scene.transition.animateProgress
+import com.android.mechanics.ProvidedGestureContext
+import com.android.mechanics.spec.InputDirection
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
@@ -55,6 +57,8 @@ internal fun PredictiveBackHandler(
// compute the distance. In our case the distance is always 1f.
orientation = Orientation.Horizontal,
distance = 1f,
+ gestureContext =
+ ProvidedGestureContext(dragOffset = 0f, direction = InputDirection.Max),
)
animateProgress(
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 de428a7d3548..a1117e1bc1db 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
@@ -30,6 +30,7 @@ import androidx.compose.ui.input.pointer.PointerType
import androidx.compose.ui.layout.LookaheadScope
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.platform.LocalViewConfiguration
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
@@ -263,9 +264,6 @@ interface BaseContentScope : ElementStateScope {
)
}
-@Deprecated("Use ContentScope instead", ReplaceWith("ContentScope"))
-typealias SceneScope = ContentScope
-
@Stable
@ElementDsl
interface ContentScope : BaseContentScope {
@@ -457,7 +455,7 @@ data class Swipe
private constructor(
val direction: SwipeDirection,
val pointerCount: Int = 1,
- val pointersType: PointerType? = null,
+ val pointerType: PointerType? = null,
val fromSource: SwipeSource? = null,
) : UserAction() {
companion object {
@@ -470,46 +468,46 @@ private constructor(
fun Left(
pointerCount: Int = 1,
- pointersType: PointerType? = null,
+ pointerType: PointerType? = null,
fromSource: SwipeSource? = null,
- ) = Swipe(SwipeDirection.Left, pointerCount, pointersType, fromSource)
+ ) = Swipe(SwipeDirection.Left, pointerCount, pointerType, fromSource)
fun Up(
pointerCount: Int = 1,
- pointersType: PointerType? = null,
+ pointerType: PointerType? = null,
fromSource: SwipeSource? = null,
- ) = Swipe(SwipeDirection.Up, pointerCount, pointersType, fromSource)
+ ) = Swipe(SwipeDirection.Up, pointerCount, pointerType, fromSource)
fun Right(
pointerCount: Int = 1,
- pointersType: PointerType? = null,
+ pointerType: PointerType? = null,
fromSource: SwipeSource? = null,
- ) = Swipe(SwipeDirection.Right, pointerCount, pointersType, fromSource)
+ ) = Swipe(SwipeDirection.Right, pointerCount, pointerType, fromSource)
fun Down(
pointerCount: Int = 1,
- pointersType: PointerType? = null,
+ pointerType: PointerType? = null,
fromSource: SwipeSource? = null,
- ) = Swipe(SwipeDirection.Down, pointerCount, pointersType, fromSource)
+ ) = Swipe(SwipeDirection.Down, pointerCount, pointerType, fromSource)
fun Start(
pointerCount: Int = 1,
- pointersType: PointerType? = null,
+ pointerType: PointerType? = null,
fromSource: SwipeSource? = null,
- ) = Swipe(SwipeDirection.Start, pointerCount, pointersType, fromSource)
+ ) = Swipe(SwipeDirection.Start, pointerCount, pointerType, fromSource)
fun End(
pointerCount: Int = 1,
- pointersType: PointerType? = null,
+ pointerType: PointerType? = null,
fromSource: SwipeSource? = null,
- ) = Swipe(SwipeDirection.End, pointerCount, pointersType, fromSource)
+ ) = Swipe(SwipeDirection.End, pointerCount, pointerType, fromSource)
}
override fun resolve(layoutDirection: LayoutDirection): UserAction.Resolved {
return Resolved(
direction = direction.resolve(layoutDirection),
pointerCount = pointerCount,
- pointersType = pointersType,
+ pointerType = pointerType,
fromSource = fromSource?.resolve(layoutDirection),
)
}
@@ -519,7 +517,7 @@ private constructor(
val direction: SwipeDirection.Resolved,
val pointerCount: Int,
val fromSource: SwipeSource.Resolved?,
- val pointersType: PointerType?,
+ val pointerType: PointerType?,
) : UserAction.Resolved()
}
@@ -716,6 +714,7 @@ internal fun SceneTransitionLayoutForTesting(
builder: SceneTransitionLayoutScope.() -> Unit,
) {
val density = LocalDensity.current
+ val directionChangeSlop = LocalViewConfiguration.current.touchSlop
val layoutDirection = LocalLayoutDirection.current
val animationScope = rememberCoroutineScope()
val layoutImpl = remember {
@@ -724,12 +723,14 @@ internal fun SceneTransitionLayoutForTesting(
density = density,
layoutDirection = layoutDirection,
swipeSourceDetector = swipeSourceDetector,
+ swipeDetector = swipeDetector,
transitionInterceptionThreshold = transitionInterceptionThreshold,
builder = builder,
animationScope = animationScope,
elements = sharedElementMap,
ancestors = ancestors,
lookaheadScope = lookaheadScope,
+ directionChangeSlop = directionChangeSlop,
)
.also { onLayoutImpl?.invoke(it) }
}
@@ -767,8 +768,9 @@ internal fun SceneTransitionLayoutForTesting(
layoutImpl.density = density
layoutImpl.layoutDirection = layoutDirection
layoutImpl.swipeSourceDetector = swipeSourceDetector
+ layoutImpl.swipeDetector = swipeDetector
layoutImpl.transitionInterceptionThreshold = transitionInterceptionThreshold
}
- layoutImpl.Content(modifier, swipeDetector)
+ layoutImpl.Content(modifier)
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index e5bdc92b5762..38ad0a80fd00 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -31,6 +31,9 @@ import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
+import androidx.compose.ui.input.nestedscroll.NestedScrollDispatcher
+import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.layout.ApproachLayoutModifierNode
import androidx.compose.ui.layout.ApproachMeasureScope
import androidx.compose.ui.layout.LookaheadScope
@@ -49,10 +52,8 @@ import com.android.compose.animation.scene.content.Content
import com.android.compose.animation.scene.content.Overlay
import com.android.compose.animation.scene.content.Scene
import com.android.compose.animation.scene.content.state.TransitionState
-import com.android.compose.animation.scene.effect.GestureEffect
import com.android.compose.ui.util.lerp
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
/** The type for the content of movable elements. */
internal typealias MovableElementContent = @Composable (@Composable () -> Unit) -> Unit
@@ -75,6 +76,7 @@ internal class SceneTransitionLayoutImpl(
internal var density: Density,
internal var layoutDirection: LayoutDirection,
internal var swipeSourceDetector: SwipeSourceDetector,
+ internal var swipeDetector: SwipeDetector,
internal var transitionInterceptionThreshold: Float,
builder: SceneTransitionLayoutScope.() -> Unit,
@@ -86,6 +88,14 @@ internal class SceneTransitionLayoutImpl(
internal val animationScope: CoroutineScope,
/**
+ * Number of pixels a gesture has to travel in the opposite direction to for its intrinsic
+ * direction to change.
+ *
+ * Used to determine the direction of [Transition.gestureContext].
+ */
+ internal val directionChangeSlop: Float,
+
+ /**
* The map of [Element]s.
*
* Important: [Element]s from this map should never be accessed during composition because the
@@ -149,18 +159,6 @@ internal class SceneTransitionLayoutImpl(
_movableContents = it
}
- internal var horizontalOverscrollableContent =
- OverscrollableContent(
- animationScope = animationScope,
- overscrollEffect = { content(it).scope.horizontalOverscrollGestureEffect },
- )
-
- internal var verticalOverscrollableContent =
- OverscrollableContent(
- animationScope = animationScope,
- overscrollEffect = { content(it).scope.verticalOverscrollGestureEffect },
- )
-
/**
* The different values of a shared value keyed by a a [ValueKey] and the different elements and
* contents it is associated to.
@@ -175,8 +173,8 @@ internal class SceneTransitionLayoutImpl(
}
// TODO(b/317958526): Lazily allocate scene gesture handlers the first time they are needed.
- internal val horizontalDraggableHandler: DraggableHandlerImpl
- internal val verticalDraggableHandler: DraggableHandlerImpl
+ internal val horizontalDraggableHandler: DraggableHandler
+ internal val verticalDraggableHandler: DraggableHandler
internal val elementStateScope = ElementStateScopeImpl(this)
internal val propertyTransformationScope = PropertyTransformationScopeImpl(this)
@@ -190,16 +188,33 @@ internal class SceneTransitionLayoutImpl(
internal var lastSize: IntSize = IntSize.Zero
+ /**
+ * An empty [NestedScrollDispatcher] and [NestedScrollConnection]. These are composed above our
+ * [SwipeToSceneElement] modifiers, so that the dispatcher will be used by the nested draggables
+ * to launch fling events, making sure that they are not cancelled unless this whole layout is
+ * removed from composition.
+ */
+ private val nestedScrollDispatcher = NestedScrollDispatcher()
+ private val nestedScrollConnection = object : NestedScrollConnection {}
+
init {
updateContents(builder, layoutDirection)
// DraggableHandlerImpl must wait for the scenes to be initialized, in order to access the
// current scene (required for SwipeTransition).
horizontalDraggableHandler =
- DraggableHandlerImpl(layoutImpl = this, orientation = Orientation.Horizontal)
+ DraggableHandler(
+ layoutImpl = this,
+ orientation = Orientation.Horizontal,
+ gestureEffectProvider = { content(it).scope.horizontalOverscrollGestureEffect },
+ )
verticalDraggableHandler =
- DraggableHandlerImpl(layoutImpl = this, orientation = Orientation.Vertical)
+ DraggableHandler(
+ layoutImpl = this,
+ orientation = Orientation.Vertical,
+ gestureEffectProvider = { content(it).scope.verticalOverscrollGestureEffect },
+ )
// Make sure that the state is created on the same thread (most probably the main thread)
// than this STLImpl.
@@ -361,6 +376,7 @@ internal class SceneTransitionLayoutImpl(
error("Transition to the same scene is not supported. ${details()}")
}
}
+
is UserActionResult.ReplaceByOverlay -> {
check(key is OverlayKey) {
"ReplaceByOverlay() can only be used for overlays, not scenes. ${details()}"
@@ -370,6 +386,7 @@ internal class SceneTransitionLayoutImpl(
"Transition to the same overlay is not supported. ${details()}"
}
}
+
is UserActionResult.ShowOverlay,
is UserActionResult.HideOverlay -> {
/* Always valid. */
@@ -379,14 +396,15 @@ internal class SceneTransitionLayoutImpl(
}
@Composable
- internal fun Content(modifier: Modifier, swipeDetector: SwipeDetector) {
+ internal fun Content(modifier: Modifier) {
Box(
modifier
+ .nestedScroll(nestedScrollConnection, nestedScrollDispatcher)
// Handle horizontal and vertical swipes on this layout.
// Note: order here is important and will give a slight priority to the vertical
// swipes.
- .swipeToScene(horizontalDraggableHandler, swipeDetector)
- .swipeToScene(verticalDraggableHandler, swipeDetector)
+ .swipeToScene(horizontalDraggableHandler)
+ .swipeToScene(verticalDraggableHandler)
.then(LayoutElement(layoutImpl = this))
) {
LookaheadScope {
@@ -435,8 +453,10 @@ internal class SceneTransitionLayoutImpl(
maybeAdd(transition.toScene)
maybeAdd(transition.fromScene)
}
+
is TransitionState.Transition.ShowOrHideOverlay ->
maybeAdd(transition.fromOrToScene)
+
is TransitionState.Transition.ReplaceOverlay -> {}
}
}
@@ -502,6 +522,7 @@ internal class SceneTransitionLayoutImpl(
is TransitionState.Transition.ChangeScene -> {}
is TransitionState.Transition.ShowOrHideOverlay ->
maybeAdd(transition.overlay)
+
is TransitionState.Transition.ReplaceOverlay -> {
maybeAdd(transition.fromOverlay)
maybeAdd(transition.toOverlay)
@@ -580,23 +601,3 @@ private class LayoutNode(var layoutImpl: SceneTransitionLayoutImpl) :
return layout(width, height) { placeable.place(0, 0) }
}
}
-
-internal class OverscrollableContent(
- private val animationScope: CoroutineScope,
- private val overscrollEffect: (ContentKey) -> GestureEffect,
-) {
- private var currentContent: ContentKey? = null
- var currentOverscrollEffect: GestureEffect? = null
-
- fun applyOverscrollEffectOn(contentKey: ContentKey): GestureEffect {
- if (currentContent == contentKey) return currentOverscrollEffect!!
-
- currentOverscrollEffect?.apply { animationScope.launch { ensureApplyToFlingIsCalled() } }
-
- // We are wrapping the overscroll effect.
- val overscrollEffect = overscrollEffect(contentKey)
- currentContent = contentKey
- currentOverscrollEffect = overscrollEffect
- return overscrollEffect
- }
-}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
index 2bfa0199f30b..4137f5f5725b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
@@ -21,11 +21,13 @@ import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.AnimationVector1D
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
+import androidx.compose.ui.util.fastCoerceIn
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.animation.scene.content.state.TransitionState.Companion.DistanceUnspecified
+import com.android.mechanics.GestureContext
+import com.android.mechanics.MutableDragOffsetGestureContext
import kotlin.math.absoluteValue
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.launch
@@ -36,6 +38,7 @@ internal fun createSwipeAnimation(
isUpOrLeft: Boolean,
orientation: Orientation,
distance: Float,
+ gestureContext: MutableDragOffsetGestureContext,
): SwipeAnimation<*> {
return createSwipeAnimation(
layoutState,
@@ -46,6 +49,7 @@ internal fun createSwipeAnimation(
contentForUserActions = {
error("Computing contentForUserActions requires a SceneTransitionLayoutImpl")
},
+ gestureContext = gestureContext,
)
}
@@ -54,6 +58,7 @@ internal fun createSwipeAnimation(
result: UserActionResult,
isUpOrLeft: Boolean,
orientation: Orientation,
+ gestureContext: MutableDragOffsetGestureContext,
distance: Float = DistanceUnspecified,
): SwipeAnimation<*> {
var lastDistance = distance
@@ -76,7 +81,16 @@ internal fun createSwipeAnimation(
return DistanceUnspecified
}
- val distance = if (isUpOrLeft) -absoluteDistance else absoluteDistance
+ // Compute the signed distance and make sure that the offset is always coerced in the right
+ // range.
+ val distance =
+ if (isUpOrLeft) {
+ animation.dragOffset = animation.dragOffset.fastCoerceIn(-absoluteDistance, 0f)
+ -absoluteDistance
+ } else {
+ animation.dragOffset = animation.dragOffset.fastCoerceIn(0f, absoluteDistance)
+ absoluteDistance
+ }
lastDistance = distance
return distance
}
@@ -88,6 +102,7 @@ internal fun createSwipeAnimation(
orientation,
distance = ::distance,
contentForUserActions = { layoutImpl.contentForUserActions().key },
+ gestureContext = gestureContext,
)
}
@@ -98,6 +113,7 @@ private fun createSwipeAnimation(
orientation: Orientation,
distance: (SwipeAnimation<*>) -> Float,
contentForUserActions: () -> ContentKey,
+ gestureContext: MutableDragOffsetGestureContext,
): SwipeAnimation<*> {
fun <T : ContentKey> swipeAnimation(fromContent: T, toContent: T): SwipeAnimation<T> {
return SwipeAnimation(
@@ -108,6 +124,7 @@ private fun createSwipeAnimation(
isUpOrLeft = isUpOrLeft,
requiresFullDistanceSwipe = result.requiresFullDistanceSwipe,
distance = distance,
+ gestureContext = gestureContext,
)
}
@@ -122,6 +139,7 @@ private fun createSwipeAnimation(
)
.swipeAnimation
}
+
is UserActionResult.ShowOverlay -> {
val fromScene = layoutState.currentScene
val overlay = result.overlay
@@ -134,6 +152,7 @@ private fun createSwipeAnimation(
)
.swipeAnimation
}
+
is UserActionResult.HideOverlay -> {
val toScene = layoutState.currentScene
val overlay = result.overlay
@@ -146,11 +165,13 @@ private fun createSwipeAnimation(
)
.swipeAnimation
}
+
is UserActionResult.ReplaceByOverlay -> {
val fromOverlay =
when (val contentForUserActions = contentForUserActions()) {
is SceneKey ->
error("ReplaceByOverlay can only be called when an overlay is shown")
+
is OverlayKey -> contentForUserActions
}
@@ -176,8 +197,8 @@ internal class SwipeAnimation<T : ContentKey>(
val requiresFullDistanceSwipe: Boolean,
private val distance: (SwipeAnimation<T>) -> Float,
currentContent: T = fromContent,
- dragOffset: Float = 0f,
-) {
+ private val gestureContext: MutableDragOffsetGestureContext,
+) : MutableDragOffsetGestureContext by gestureContext {
/** The [TransitionState.Transition] whose implementation delegates to this [SwipeAnimation]. */
lateinit var contentTransition: TransitionState.Transition
@@ -244,9 +265,6 @@ internal class SwipeAnimation<T : ContentKey>(
val isInPreviewStage: Boolean
get() = contentTransition.previewTransformationSpec != null && currentContent == fromContent
- /** The current offset caused by the drag gesture. */
- var dragOffset by mutableFloatStateOf(dragOffset)
-
/** The offset animation that animates the offset once the user lifts their finger. */
private var offsetAnimation: Animatable<Float, AnimationVector1D>? by mutableStateOf(null)
private val offsetAnimationRunnable = CompletableDeferred<suspend () -> Unit>()
@@ -294,12 +312,10 @@ internal class SwipeAnimation<T : ContentKey>(
initialVelocity: Float,
targetContent: T,
spec: AnimationSpec<Float>? = null,
- overscrollCompletable: CompletableDeferred<Unit>? = null,
+ awaitFling: (suspend () -> Unit)? = null,
): Float {
check(!isAnimatingOffset()) { "SwipeAnimation.animateOffset() can only be called once" }
- val initialProgress = progress
-
val targetContent =
if (targetContent != currentContent && !canChangeContent(targetContent)) {
currentContent
@@ -307,18 +323,16 @@ internal class SwipeAnimation<T : ContentKey>(
targetContent
}
- // Skip the animation if we have already reached the target content and the overscroll does
- // not animate anything.
- val hasReachedTargetContent =
- (targetContent == toContent && initialProgress >= 1f) ||
- (targetContent == fromContent && initialProgress <= 0f)
- val skipAnimation =
- hasReachedTargetContent && !contentTransition.isWithinProgressRange(initialProgress)
-
val distance = distance()
- check(distance != DistanceUnspecified) { "distance is equal to $DistanceUnspecified" }
-
- val targetOffset = if (targetContent == fromContent) 0f else distance
+ val targetOffset =
+ if (targetContent == fromContent) {
+ 0f
+ } else {
+ check(distance != DistanceUnspecified) {
+ "distance is equal to $DistanceUnspecified"
+ }
+ distance
+ }
// If the effective current content changed, it should be reflected right now in the
// current state, even before the settle animation is ongoing. That way all the
@@ -350,28 +364,12 @@ internal class SwipeAnimation<T : ContentKey>(
check(isAnimatingOffset())
- // Note: we still create the animatable and set it on offsetAnimation even when
- // skipAnimation is true, just so that isUserInputOngoing and isAnimatingOffset() are
- // unchanged even despite this small skip-optimization (which is just an implementation
- // detail).
- if (skipAnimation) {
- // Unblock the job.
- offsetAnimationRunnable.complete {
- // Wait for overscroll to finish so that the transition is removed from the STLState
- // only after the overscroll is done, to avoid dropping frame right when the user
- // lifts their finger and overscroll is animated to 0.
- overscrollCompletable?.await()
- }
- return 0f
- }
-
val motionSpatialSpec =
spec
?: contentTransition.transformationSpec.motionSpatialSpec
?: layoutState.transitions.defaultMotionSpatialSpec
val velocityConsumed = CompletableDeferred<Float>()
-
offsetAnimationRunnable.complete {
val result =
animatable.animateTo(
@@ -385,9 +383,9 @@ internal class SwipeAnimation<T : ContentKey>(
velocityConsumed.complete(initialVelocity - result.endState.velocity)
// Wait for overscroll to finish so that the transition is removed from the STLState
- // only after the overscroll is done, to avoid dropping frame right when the user
- // lifts their finger and overscroll is animated to 0.
- overscrollCompletable?.await()
+ // only after the overscroll is done, to avoid dropping frame right when the user lifts
+ // their finger and overscroll is animated to 0.
+ awaitFling?.invoke()
}
return velocityConsumed.await()
@@ -397,6 +395,7 @@ internal class SwipeAnimation<T : ContentKey>(
return when (val transition = contentTransition) {
is TransitionState.Transition.ChangeScene ->
layoutState.canChangeScene(targetContent as SceneKey)
+
is TransitionState.Transition.ShowOrHideOverlay -> {
if (targetContent == transition.overlay) {
layoutState.canShowOverlay(transition.overlay)
@@ -404,6 +403,7 @@ internal class SwipeAnimation<T : ContentKey>(
layoutState.canHideOverlay(transition.overlay)
}
}
+
is TransitionState.Transition.ReplaceOverlay -> {
val to = targetContent as OverlayKey
val from =
@@ -474,6 +474,8 @@ private class ChangeSceneSwipeTransition(
override val isUserInputOngoing: Boolean
get() = swipeAnimation.isUserInputOngoing
+ override val gestureContext: GestureContext = swipeAnimation
+
override suspend fun run() {
swipeAnimation.run()
}
@@ -525,6 +527,8 @@ private class ShowOrHideOverlaySwipeTransition(
override val isUserInputOngoing: Boolean
get() = swipeAnimation.isUserInputOngoing
+ override val gestureContext: GestureContext = swipeAnimation
+
override suspend fun run() {
swipeAnimation.run()
}
@@ -572,6 +576,8 @@ private class ReplaceOverlaySwipeTransition(
override val isUserInputOngoing: Boolean
get() = swipeAnimation.isUserInputOngoing
+ override val gestureContext: GestureContext = swipeAnimation
+
override suspend fun run() {
swipeAnimation.run()
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
index e2212113404d..19f707df91e0 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
@@ -19,153 +19,35 @@ package com.android.compose.animation.scene
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.Stable
import androidx.compose.ui.Modifier
-import androidx.compose.ui.input.nestedscroll.NestedScrollDispatcher
-import androidx.compose.ui.input.nestedscroll.nestedScrollModifierNode
-import androidx.compose.ui.input.pointer.PointerEvent
-import androidx.compose.ui.input.pointer.PointerEventPass
-import androidx.compose.ui.node.DelegatingNode
-import androidx.compose.ui.node.ModifierNodeElement
-import androidx.compose.ui.node.PointerInputModifierNode
-import androidx.compose.ui.unit.IntSize
import com.android.compose.animation.scene.content.Content
+import com.android.compose.gesture.nestedDraggable
/**
* Configures the swipeable behavior of a [SceneTransitionLayout] depending on the current state.
*/
@Stable
-internal fun Modifier.swipeToScene(
- draggableHandler: DraggableHandlerImpl,
- swipeDetector: SwipeDetector,
-): Modifier {
- return then(SwipeToSceneElement(draggableHandler, swipeDetector, draggableHandler.enabled()))
+internal fun Modifier.swipeToScene(draggableHandler: DraggableHandler): Modifier {
+ return this.nestedDraggable(
+ draggable = draggableHandler,
+ orientation = draggableHandler.orientation,
+ overscrollEffect = draggableHandler.overscrollEffect,
+ enabled = draggableHandler.enabled(),
+ )
}
-private fun DraggableHandlerImpl.enabled(): Boolean {
+internal fun DraggableHandler.enabled(): Boolean {
return isDrivingTransition || contentForSwipes().shouldEnableSwipes(orientation)
}
-private fun DraggableHandlerImpl.contentForSwipes(): Content {
+private fun DraggableHandler.contentForSwipes(): Content {
return layoutImpl.contentForUserActions()
}
/** Whether swipe should be enabled in the given [orientation]. */
-internal fun Content.shouldEnableSwipes(orientation: Orientation): Boolean {
+private fun Content.shouldEnableSwipes(orientation: Orientation): Boolean {
if (userActions.isEmpty() || !areSwipesAllowed()) {
return false
}
return userActions.keys.any { it is Swipe.Resolved && it.direction.orientation == orientation }
}
-
-private data class SwipeToSceneElement(
- val draggableHandler: DraggableHandlerImpl,
- val swipeDetector: SwipeDetector,
- val enabled: Boolean,
-) : ModifierNodeElement<SwipeToSceneRootNode>() {
- override fun create(): SwipeToSceneRootNode =
- SwipeToSceneRootNode(draggableHandler, swipeDetector, enabled)
-
- override fun update(node: SwipeToSceneRootNode) {
- node.update(draggableHandler, swipeDetector, enabled)
- }
-}
-
-private class SwipeToSceneRootNode(
- draggableHandler: DraggableHandlerImpl,
- swipeDetector: SwipeDetector,
- enabled: Boolean,
-) : DelegatingNode() {
- private var delegateNode = if (enabled) create(draggableHandler, swipeDetector) else null
-
- fun update(
- draggableHandler: DraggableHandlerImpl,
- swipeDetector: SwipeDetector,
- enabled: Boolean,
- ) {
- // Disabled.
- if (!enabled) {
- delegateNode?.let { undelegate(it) }
- delegateNode = null
- return
- }
-
- // Disabled => Enabled.
- val nullableDelegate = delegateNode
- if (nullableDelegate == null) {
- delegateNode = create(draggableHandler, swipeDetector)
- return
- }
-
- // Enabled => Enabled (update).
- if (draggableHandler == nullableDelegate.draggableHandler) {
- // Simple update, just update the swipe detector directly and keep the node.
- nullableDelegate.swipeDetector = swipeDetector
- } else {
- // The draggableHandler changed, force recreate the underlying SwipeToSceneNode.
- undelegate(nullableDelegate)
- delegateNode = create(draggableHandler, swipeDetector)
- }
- }
-
- private fun create(
- draggableHandler: DraggableHandlerImpl,
- swipeDetector: SwipeDetector,
- ): SwipeToSceneNode {
- return delegate(SwipeToSceneNode(draggableHandler, swipeDetector))
- }
-}
-
-private class SwipeToSceneNode(
- val draggableHandler: DraggableHandlerImpl,
- swipeDetector: SwipeDetector,
-) : DelegatingNode(), PointerInputModifierNode {
- private val dispatcher = NestedScrollDispatcher()
- private val multiPointerDraggableNode =
- delegate(
- MultiPointerDraggableNode(
- orientation = draggableHandler.orientation,
- onDragStarted = draggableHandler::onDragStarted,
- onFirstPointerDown = ::onFirstPointerDown,
- swipeDetector = swipeDetector,
- dispatcher = dispatcher,
- )
- )
-
- var swipeDetector: SwipeDetector
- get() = multiPointerDraggableNode.swipeDetector
- set(value) {
- multiPointerDraggableNode.swipeDetector = value
- }
-
- private val nestedScrollHandlerImpl =
- NestedScrollHandlerImpl(
- draggableHandler = draggableHandler,
- pointersInfoOwner = { multiPointerDraggableNode.pointersInfo() },
- )
-
- init {
- delegate(nestedScrollModifierNode(nestedScrollHandlerImpl.connection, dispatcher))
- }
-
- private fun onFirstPointerDown() {
- // When we drag our finger across the screen, the NestedScrollConnection keeps track of all
- // the scroll events until we lift our finger. However, in some cases, the connection might
- // not receive the "up" event. This can lead to an incorrect initial state for the gesture.
- // To prevent this issue, we can call the reset() method when the first finger touches the
- // screen. This ensures that the NestedScrollConnection starts from a correct state.
- nestedScrollHandlerImpl.connection.reset()
- }
-
- override fun onDetach() {
- // Make sure we reset the scroll connection when this modifier is removed from composition
- nestedScrollHandlerImpl.connection.reset()
- }
-
- override fun onPointerEvent(
- pointerEvent: PointerEvent,
- pass: PointerEventPass,
- bounds: IntSize,
- ) = multiPointerDraggableNode.onPointerEvent(pointerEvent, pass, bounds)
-
- override fun onCancelPointerInput() = multiPointerDraggableNode.onCancelPointerInput()
-}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
index 097722665f8e..e9542c830b4d 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
@@ -33,6 +33,7 @@ import com.android.compose.animation.scene.TransformationSpec
import com.android.compose.animation.scene.TransformationSpecImpl
import com.android.compose.animation.scene.TransitionKey
import com.android.internal.jank.Cuj.CujType
+import com.android.mechanics.GestureContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
@@ -238,6 +239,9 @@ sealed interface TransitionState {
/** Whether user input is currently driving the transition. */
abstract val isUserInputOngoing: Boolean
+ /** Additional gesture context whenever the transition is driven by a user gesture. */
+ abstract val gestureContext: GestureContext?
+
/** The CUJ covered by this transition. */
@CujType
val cuj: Int?
@@ -373,15 +377,6 @@ sealed interface TransitionState {
}
}
- /**
- * Checks if the given [progress] value is within the valid range for this transition.
- *
- * The valid range is between 0f and 1f, inclusive.
- */
- internal fun isWithinProgressRange(progress: Float): Boolean {
- return progress >= 0f && progress <= 1f
- }
-
internal open fun interruptionProgress(layoutImpl: SceneTransitionLayoutImpl): Float {
if (replacedTransition != null) {
return replacedTransition.interruptionProgress(layoutImpl)
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/Seek.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/Seek.kt
index c6912d5e4ad2..819cec712808 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/Seek.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/Seek.kt
@@ -29,6 +29,8 @@ import com.android.compose.animation.scene.SwipeAnimation
import com.android.compose.animation.scene.TransitionKey
import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.createSwipeAnimation
+import com.android.mechanics.ProvidedGestureContext
+import com.android.mechanics.spec.InputDirection
import kotlin.coroutines.cancellation.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
@@ -126,6 +128,9 @@ private suspend fun MutableSceneTransitionLayoutState.seek(
// overscroll, which is disabled for progress-based transitions.
orientation = Orientation.Horizontal,
isUpOrLeft = false,
+ // There is no gesture information available here - animateProgress
+ // will set the progress as the dragOffset.
+ gestureContext = ProvidedGestureContext(0f, InputDirection.Max),
)
animateProgress(
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
index 5a9edba26d13..ef360770bc41 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
@@ -38,9 +38,13 @@ import com.android.compose.animation.scene.TestScenes.SceneC
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.animation.scene.content.state.TransitionState.Transition
import com.android.compose.animation.scene.subjects.assertThat
+import com.android.compose.gesture.NestedDraggable
import com.android.compose.test.MonotonicClockTestScope
import com.android.compose.test.runMonotonicClockTest
+import com.android.mechanics.spec.InputDirection
import com.google.common.truth.Truth.assertThat
+import kotlin.math.nextUp
+import kotlin.math.sign
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
@@ -51,18 +55,6 @@ import org.junit.runner.RunWith
private const val SCREEN_SIZE = 100f
private val LAYOUT_SIZE = IntSize(SCREEN_SIZE.toInt(), SCREEN_SIZE.toInt())
-private fun pointersDown(
- startedPosition: Offset = Offset.Zero,
- pointersDown: Int = 1,
- pointersDownByType: Map<PointerType, Int> = mapOf(PointerType.Touch to pointersDown),
-): PointersInfo.PointersDown {
- return PointersInfo.PointersDown(
- startedPosition = startedPosition,
- count = pointersDown,
- countByType = pointersDownByType,
- )
-}
-
@RunWith(AndroidJUnit4::class)
class DraggableHandlerTest {
private class TestGestureScope(val testScope: MonotonicClockTestScope) {
@@ -116,6 +108,7 @@ class DraggableHandlerTest {
}
val transitionInterceptionThreshold = 0.05f
+ val directionChangeSlop = 10f
private val layoutImpl =
SceneTransitionLayoutImpl(
@@ -123,20 +116,19 @@ class DraggableHandlerTest {
density = Density(1f),
layoutDirection = LayoutDirection.Ltr,
swipeSourceDetector = DefaultEdgeDetector,
+ swipeDetector = DefaultSwipeDetector,
transitionInterceptionThreshold = transitionInterceptionThreshold,
builder = scenesBuilder,
// Use testScope and not backgroundScope here because backgroundScope does not
// work well with advanceUntilIdle(), which is used by some tests.
animationScope = testScope,
+ directionChangeSlop = directionChangeSlop,
)
.apply { setContentsAndLayoutTargetSizeForTest(LAYOUT_SIZE) }
val draggableHandler = layoutImpl.verticalDraggableHandler
val horizontalDraggableHandler = layoutImpl.horizontalDraggableHandler
-
- var pointerInfoOwner: () -> PointersInfo = { pointersDown() }
-
val velocityThreshold = draggableHandler.velocityThreshold
fun down(fractionOfScreen: Float) =
@@ -204,41 +196,51 @@ class DraggableHandlerTest {
}
fun onDragStarted(
- pointersInfo: PointersInfo.PointersDown = pointersDown(),
overSlop: Float,
+ position: Offset = Offset.Zero,
+ pointersDown: Int = 1,
+ pointerType: PointerType? = PointerType.Touch,
expectedConsumedOverSlop: Float = overSlop,
- ): DragController {
- // overSlop should be 0f only if the drag gesture starts with startDragImmediately
- if (overSlop == 0f) error("Consider using onDragStartedImmediately()")
+ ): NestedDraggable.Controller {
return onDragStarted(
draggableHandler = draggableHandler,
- pointersInfo = pointersInfo,
overSlop = overSlop,
+ position = position,
+ pointersDown = pointersDown,
+ pointerType = pointerType,
expectedConsumedOverSlop = expectedConsumedOverSlop,
)
}
fun onDragStarted(
- draggableHandler: DraggableHandler,
- pointersInfo: PointersInfo.PointersDown = pointersDown(),
- overSlop: Float = 0f,
+ draggableHandler: NestedDraggable,
+ overSlop: Float,
+ position: Offset = Offset.Zero,
+ pointersDown: Int = 1,
+ pointerType: PointerType? = PointerType.Touch,
expectedConsumedOverSlop: Float = overSlop,
- ): DragController {
+ ): NestedDraggable.Controller {
+ // overSlop should be 0f only if the drag gesture starts with startDragImmediately.
+ if (overSlop == 0f) error("Consider using onDragStartedImmediately()")
+
val dragController =
- draggableHandler.onDragStarted(pointersDown = pointersInfo, overSlop = overSlop)
+ draggableHandler.onDragStarted(position, overSlop.sign, pointersDown, pointerType)
- // MultiPointerDraggable will always call onDelta with the initial overSlop right after
+ // MultiPointerDraggable will always call onDelta with the initial overSlop right after.
dragController.onDragDelta(pixels = overSlop, expectedConsumedOverSlop)
return dragController
}
- fun DragController.onDragDelta(pixels: Float, expectedConsumed: Float = pixels) {
+ fun NestedDraggable.Controller.onDragDelta(
+ pixels: Float,
+ expectedConsumed: Float = pixels,
+ ) {
val consumed = onDrag(delta = pixels)
assertThat(consumed).isEqualTo(expectedConsumed)
}
- suspend fun DragController.onDragStoppedAnimateNow(
+ suspend fun NestedDraggable.Controller.onDragStoppedAnimateNow(
velocity: Float,
onAnimationStart: () -> Unit,
onAnimationEnd: (Float) -> Unit,
@@ -248,7 +250,7 @@ class DraggableHandlerTest {
onAnimationEnd(velocityConsumed.await())
}
- suspend fun DragController.onDragStoppedAnimateNow(
+ suspend fun NestedDraggable.Controller.onDragStoppedAnimateNow(
velocity: Float,
onAnimationStart: () -> Unit,
) =
@@ -258,8 +260,8 @@ class DraggableHandlerTest {
onAnimationEnd = {},
)
- fun DragController.onDragStoppedAnimateLater(velocity: Float): Deferred<Float> {
- val velocityConsumed = testScope.async { onStop(velocity) }
+ fun NestedDraggable.Controller.onDragStoppedAnimateLater(velocity: Float): Deferred<Float> {
+ val velocityConsumed = testScope.async { onDragStopped(velocity, awaitFling = {}) }
testScope.testScheduler.runCurrent()
return velocityConsumed
}
@@ -408,12 +410,13 @@ class DraggableHandlerTest {
}
@Test
- fun onDragIntoNoAction_stayIdle() = runGestureTest {
+ fun onDragIntoNoAction_overscrolls() = runGestureTest {
navigateToSceneC()
- // We are on SceneC which has no action in Down direction
+ // We are on SceneC which has no action in Down direction, we still start a transition so
+ // that we can overscroll on that scene.
onDragStarted(overSlop = 10f, expectedConsumedOverSlop = 0f)
- assertIdle(currentScene = SceneC)
+ assertTransition(fromScene = SceneC, toScene = SceneB, progress = 0f)
}
@Test
@@ -422,8 +425,7 @@ class DraggableHandlerTest {
mutableUserActionsA = mapOf(Swipe.Up to UserActionResult(SceneB), Swipe.Down to SceneC)
val dragController =
onDragStarted(
- pointersInfo =
- pointersDown(startedPosition = Offset(SCREEN_SIZE * 0.5f, SCREEN_SIZE * 0.5f)),
+ position = Offset(SCREEN_SIZE * 0.5f, SCREEN_SIZE * 0.5f),
overSlop = up(fractionOfScreen = 0.2f),
)
assertTransition(
@@ -447,7 +449,7 @@ class DraggableHandlerTest {
// Start dragging from the bottom
onDragStarted(
- pointersInfo = pointersDown(startedPosition = Offset(SCREEN_SIZE * 0.5f, SCREEN_SIZE)),
+ position = Offset(SCREEN_SIZE * 0.5f, SCREEN_SIZE),
overSlop = up(fractionOfScreen = 0.1f),
)
assertTransition(
@@ -548,8 +550,7 @@ class DraggableHandlerTest {
navigateToSceneC()
// Swipe up from the middle to transition to scene B.
- val middle = pointersDown(startedPosition = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f))
- onDragStarted(pointersInfo = middle, overSlop = up(0.1f))
+ onDragStarted(position = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f), overSlop = up(0.1f))
assertTransition(fromScene = SceneC, toScene = SceneB, isUserInputOngoing = true)
// Freeze the transition.
@@ -602,8 +603,11 @@ class DraggableHandlerTest {
@Test
fun transitionIsImmediatelyUpdatedWhenReleasingFinger() = runGestureTest {
// Swipe up from the middle to transition to scene B.
- val middle = pointersDown(startedPosition = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f))
- val dragController = onDragStarted(pointersInfo = middle, overSlop = up(0.1f))
+ val dragController =
+ onDragStarted(
+ position = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f),
+ overSlop = up(0.1f),
+ )
assertTransition(fromScene = SceneA, toScene = SceneB, isUserInputOngoing = true)
dragController.onDragStoppedAnimateLater(velocity = 0f)
@@ -613,8 +617,11 @@ class DraggableHandlerTest {
@Test
fun emptyOverscrollAbortsSettleAnimationAndExposeTheConsumedVelocity() = runGestureTest {
// Swipe up to scene B at progress = 200%.
- val middle = pointersDown(startedPosition = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f))
- val dragController = onDragStarted(pointersInfo = middle, overSlop = up(0.99f))
+ val dragController =
+ onDragStarted(
+ position = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f),
+ overSlop = up(0.99f),
+ )
assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.99f)
// Release the finger.
@@ -638,9 +645,11 @@ class DraggableHandlerTest {
from(SceneA, to = SceneB) {}
}
- val middle = pointersDown(startedPosition = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f))
-
- val dragController = onDragStarted(pointersInfo = middle, overSlop = up(0.5f))
+ val dragController =
+ onDragStarted(
+ position = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f),
+ overSlop = up(0.5f),
+ )
val transition = assertThat(transitionState).isSceneTransition()
assertThat(transition).hasFromScene(SceneA)
assertThat(transition).hasToScene(SceneB)
@@ -667,9 +676,11 @@ class DraggableHandlerTest {
from(SceneA, to = SceneC) {}
}
- val middle = pointersDown(startedPosition = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f))
-
- val dragController = onDragStarted(pointersInfo = middle, overSlop = down(0.5f))
+ val dragController =
+ onDragStarted(
+ position = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f),
+ overSlop = down(0.5f),
+ )
val transition = assertThat(transitionState).isSceneTransition()
assertThat(transition).hasFromScene(SceneA)
assertThat(transition).hasToScene(SceneC)
@@ -695,11 +706,9 @@ class DraggableHandlerTest {
from(SceneA, to = SceneB) { spec = spring(dampingRatio = Spring.DampingRatioNoBouncy) }
}
- val middle = pointersDown(startedPosition = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f))
-
val dragController =
onDragStarted(
- pointersInfo = middle,
+ position = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f),
overSlop = up(1.5f),
expectedConsumedOverSlop = up(1f),
)
@@ -729,11 +738,9 @@ class DraggableHandlerTest {
from(SceneA, to = SceneC) { spec = spring(dampingRatio = Spring.DampingRatioNoBouncy) }
}
- val middle = pointersDown(startedPosition = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f))
-
val dragController =
onDragStarted(
- pointersInfo = middle,
+ position = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f),
overSlop = down(1.5f),
expectedConsumedOverSlop = down(1f),
)
@@ -868,4 +875,65 @@ class DraggableHandlerTest {
assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
assertThat(layoutState.transitionState).hasCurrentOverlays(OverlayB)
}
+
+ @Test
+ fun gestureContext_dragOffset_matchesOverSlopAtBeginning() = runGestureTest {
+ val overSlop = down(fractionOfScreen = 0.1f)
+ onDragStarted(overSlop = overSlop)
+
+ val gestureContext = assertThat(transitionState).hasGestureContext()
+ assertThat(gestureContext.dragOffset).isEqualTo(overSlop)
+ }
+
+ @Test
+ fun gestureContext_dragOffset_getsUpdatedOnEachDragEvent() = runGestureTest {
+ val dragController = onDragStarted(overSlop = down(fractionOfScreen = 0.1f))
+
+ val gestureContext = assertThat(transitionState).hasGestureContext()
+ val initialDragOffset = gestureContext.dragOffset
+
+ dragController.onDragDelta(pixels = 3.5f)
+ assertThat(gestureContext.dragOffset).isEqualTo(initialDragOffset + 3.5f)
+
+ dragController.onDragDelta(pixels = -2f)
+ assertThat(gestureContext.dragOffset).isEqualTo(initialDragOffset + 3.5f - 2f)
+ }
+
+ @Test
+ fun gestureContext_direction_swipeDown_startsWithMaxDirection() = runGestureTest {
+ onDragStarted(overSlop = down(fractionOfScreen = 0.1f))
+
+ val gestureContext = assertThat(transitionState).hasGestureContext()
+ assertThat(gestureContext.direction).isEqualTo(InputDirection.Max)
+ }
+
+ @Test
+ fun gestureContext_direction_swipeUp_startsWithMinDirection() = runGestureTest {
+ onDragStarted(overSlop = up(fractionOfScreen = 0.1f))
+
+ val gestureContext = assertThat(transitionState).hasGestureContext()
+ assertThat(gestureContext.direction).isEqualTo(InputDirection.Min)
+ }
+
+ @Test
+ fun gestureContext_direction_withinDirectionSlop_staysSame() = runGestureTest {
+ val dragController = onDragStarted(overSlop = up(fractionOfScreen = .2f))
+
+ val gestureContext = assertThat(transitionState).hasGestureContext()
+ assertThat(gestureContext.direction).isEqualTo(InputDirection.Min)
+
+ dragController.onDragDelta(pixels = directionChangeSlop)
+ assertThat(gestureContext.direction).isEqualTo(InputDirection.Min)
+ }
+
+ @Test
+ fun gestureContext_direction_overDirectionSlop_isChanged() = runGestureTest {
+ val dragController = onDragStarted(overSlop = up(fractionOfScreen = .2f))
+
+ val gestureContext = assertThat(transitionState).hasGestureContext()
+ assertThat(gestureContext.direction).isEqualTo(InputDirection.Min)
+
+ dragController.onDragDelta(pixels = directionChangeSlop.nextUp())
+ assertThat(gestureContext.direction).isEqualTo(InputDirection.Max)
+ }
}
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 005146997813..b405fbe89302 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
@@ -2095,7 +2095,7 @@ class ElementTest {
val foo = ElementKey("Foo", placeAllCopies = true)
@Composable
- fun SceneScope.Foo(size: Dp, modifier: Modifier = Modifier) {
+ fun ContentScope.Foo(size: Dp, modifier: Modifier = Modifier) {
Box(modifier.element(foo).size(size))
}
@@ -2159,7 +2159,7 @@ class ElementTest {
// Foo is a simple element that does not move or resize during the transition.
@Composable
- fun SceneScope.Foo(modifier: Modifier = Modifier) {
+ fun ContentScope.Foo(modifier: Modifier = Modifier) {
Box(
modifier
.element(TestElements.Foo)
@@ -2211,7 +2211,7 @@ class ElementTest {
@Ignore("b/363964445")
fun interruption_considerPreviousUniqueState() {
@Composable
- fun SceneScope.Foo(modifier: Modifier = Modifier) {
+ fun ContentScope.Foo(modifier: Modifier = Modifier) {
Box(modifier.element(TestElements.Foo).size(50.dp))
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
index b4c8ad7c3327..9e1bae577ed2 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
@@ -373,7 +373,7 @@ class MovableElementTest {
val fooParentInOverlayTag = "fooParentTagInOverlay"
@Composable
- fun SceneScope.Foo(modifier: Modifier = Modifier) {
+ fun ContentScope.Foo(modifier: Modifier = Modifier) {
// Foo wraps its content, so there is no way for STL to know its size in advance.
MovableElement(foo, modifier) { content { Box(Modifier.size(fooSize)) } }
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
deleted file mode 100644
index 5c6f91bb0e90..000000000000
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
+++ /dev/null
@@ -1,866 +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.compose.animation.scene
-
-import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.foundation.gestures.rememberScrollableState
-import androidx.compose.foundation.gestures.scrollable
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.size
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Size
-import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
-import androidx.compose.ui.input.nestedscroll.NestedScrollDispatcher
-import androidx.compose.ui.input.nestedscroll.NestedScrollSource
-import androidx.compose.ui.input.nestedscroll.nestedScroll
-import androidx.compose.ui.input.pointer.AwaitPointerEventScope
-import androidx.compose.ui.input.pointer.PointerEventPass
-import androidx.compose.ui.input.pointer.PointerInputChange
-import androidx.compose.ui.input.pointer.pointerInput
-import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.platform.LocalViewConfiguration
-import androidx.compose.ui.test.TouchInjectionScope
-import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.onRoot
-import androidx.compose.ui.test.performTouchInput
-import androidx.compose.ui.unit.Density
-import androidx.compose.ui.unit.Velocity
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.android.compose.modifiers.thenIf
-import com.google.common.truth.Truth.assertThat
-import kotlin.properties.Delegates
-import kotlinx.coroutines.coroutineScope
-import kotlinx.coroutines.isActive
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-class MultiPointerDraggableTest {
- @get:Rule val rule = createComposeRule()
-
- private val emptyConnection = object : NestedScrollConnection {}
- private val defaultDispatcher = NestedScrollDispatcher()
-
- private fun Modifier.nestedScrollDispatcher() = nestedScroll(emptyConnection, defaultDispatcher)
-
- private class SimpleDragController(
- val onDrag: (delta: Float) -> Unit,
- val onStop: (velocity: Float) -> Unit,
- ) : DragController {
- override fun onDrag(delta: Float): Float {
- onDrag.invoke(delta)
- return delta
- }
-
- override suspend fun onStop(velocity: Float): Float {
- onStop.invoke(velocity)
- return velocity
- }
-
- override fun onCancel() {
- error("MultiPointerDraggable never calls onCancel()")
- }
- }
-
- @Test
- fun cancellingPointerCallsOnDragStopped() {
- val size = 200f
- val middle = Offset(size / 2f, size / 2f)
-
- var enabled by mutableStateOf(false)
- var started = false
- var dragged = false
- var stopped = false
-
- var touchSlop = 0f
- rule.setContent {
- touchSlop = LocalViewConfiguration.current.touchSlop
- Box(
- Modifier.size(with(LocalDensity.current) { Size(size, size).toDpSize() })
- .nestedScrollDispatcher()
- .thenIf(enabled) {
- Modifier.multiPointerDraggable(
- orientation = Orientation.Vertical,
- onDragStarted = { _, _ ->
- started = true
- SimpleDragController(
- onDrag = { dragged = true },
- onStop = { stopped = true },
- )
- },
- dispatcher = defaultDispatcher,
- )
- }
- )
- }
-
- fun startDraggingDown() {
- rule.onRoot().performTouchInput {
- down(middle)
- moveBy(Offset(0f, touchSlop))
- }
- }
-
- fun releaseFinger() {
- rule.onRoot().performTouchInput { up() }
- }
-
- // Swiping down does nothing because enabled is false.
- startDraggingDown()
- assertThat(started).isFalse()
- assertThat(dragged).isFalse()
- assertThat(stopped).isFalse()
- releaseFinger()
-
- // Enable the draggable and swipe down. This should both call onDragStarted() and
- // onDragDelta().
- enabled = true
- rule.waitForIdle()
- startDraggingDown()
- assertThat(started).isTrue()
- assertThat(dragged).isTrue()
- assertThat(stopped).isFalse()
-
- // Disable the pointer input. This should call onDragStopped() even if didn't release the
- // finger yet.
- enabled = false
- rule.waitForIdle()
- assertThat(started).isTrue()
- assertThat(dragged).isTrue()
- assertThat(stopped).isTrue()
- }
-
- @Test
- fun shouldNotStartDragEventsWith0PointersDown() {
- val size = 200f
- val middle = Offset(size / 2f, size / 2f)
-
- var started = false
- var dragged = false
- var stopped = false
- var consumedByDescendant = false
-
- var touchSlop = 0f
- rule.setContent {
- touchSlop = LocalViewConfiguration.current.touchSlop
- Box(
- Modifier.size(with(LocalDensity.current) { Size(size, size).toDpSize() })
- .nestedScrollDispatcher()
- .multiPointerDraggable(
- orientation = Orientation.Vertical,
- onDragStarted = { _, _ ->
- started = true
- SimpleDragController(
- onDrag = { dragged = true },
- onStop = { stopped = true },
- )
- },
- dispatcher = defaultDispatcher,
- )
- .pointerInput(Unit) {
- coroutineScope {
- awaitPointerEventScope {
- while (isActive) {
- val change = awaitPointerEvent().changes.first()
- if (consumedByDescendant) {
- change.consume()
- }
- }
- }
- }
- }
- )
- }
-
- // The first part of the gesture is consumed by our descendant
- consumedByDescendant = true
- rule.onRoot().performTouchInput {
- down(middle)
- moveBy(Offset(0f, touchSlop))
- }
-
- // The events were consumed by our descendant, we should not start a drag gesture.
- assertThat(started).isFalse()
- assertThat(dragged).isFalse()
- assertThat(stopped).isFalse()
-
- // The next events could be consumed by us
- consumedByDescendant = false
- rule.onRoot().performTouchInput {
- // The pointer is moved to a new position without reporting it
- updatePointerBy(0, Offset(0f, touchSlop))
-
- // The pointer report an "up" (0 pointers down) with a new position
- up()
- }
-
- // The "up" event should not be used to start a drag gesture
- assertThat(started).isFalse()
- assertThat(dragged).isFalse()
- assertThat(stopped).isFalse()
- }
-
- @Test
- fun handleDisappearingScrollableDuringAGesture() {
- val size = 200f
- val middle = Offset(size / 2f, size / 2f)
-
- var started = false
- var dragged = false
- var stopped = false
- var consumedByScroll = false
- var hasScrollable by mutableStateOf(true)
-
- var touchSlop = 0f
- rule.setContent {
- touchSlop = LocalViewConfiguration.current.touchSlop
- Box(
- Modifier.size(with(LocalDensity.current) { Size(size, size).toDpSize() })
- .nestedScrollDispatcher()
- .multiPointerDraggable(
- orientation = Orientation.Vertical,
- onDragStarted = { _, _ ->
- started = true
- SimpleDragController(
- onDrag = { dragged = true },
- onStop = { stopped = true },
- )
- },
- dispatcher = defaultDispatcher,
- )
- ) {
- if (hasScrollable) {
- Box(
- Modifier.scrollable(
- // Consume all the vertical scroll gestures
- rememberScrollableState(
- consumeScrollDelta = {
- consumedByScroll = true
- it
- }
- ),
- Orientation.Vertical,
- )
- .fillMaxSize()
- )
- }
- }
- }
-
- fun startDraggingDown() {
- rule.onRoot().performTouchInput {
- down(middle)
- moveBy(Offset(0f, touchSlop))
- }
- }
-
- fun continueDraggingDown() {
- rule.onRoot().performTouchInput { moveBy(Offset(0f, touchSlop)) }
- }
-
- fun releaseFinger() {
- rule.onRoot().performTouchInput { up() }
- }
-
- // Swipe down. This should intercepted by the scrollable modifier.
- startDraggingDown()
- assertThat(consumedByScroll).isTrue()
- assertThat(started).isFalse()
- assertThat(dragged).isFalse()
- assertThat(stopped).isFalse()
-
- // Reset the scroll state for the test
- consumedByScroll = false
-
- // Suddenly remove the scrollable container
- hasScrollable = false
- rule.waitForIdle()
-
- // Swipe down. This will be intercepted by multiPointerDraggable, it will wait touchSlop
- // before consuming it.
- continueDraggingDown()
- assertThat(consumedByScroll).isFalse()
- assertThat(started).isFalse()
- assertThat(dragged).isFalse()
- assertThat(stopped).isFalse()
-
- // Swipe down. This should both call onDragStarted() and onDragDelta().
- continueDraggingDown()
- assertThat(consumedByScroll).isFalse()
- assertThat(started).isTrue()
- assertThat(dragged).isTrue()
- assertThat(stopped).isFalse()
-
- rule.waitForIdle()
- releaseFinger()
- assertThat(stopped).isTrue()
- }
-
- @Test
- fun multiPointerWaitAConsumableEventInMainPass() {
- val size = 200f
- val middle = Offset(size / 2f, size / 2f)
-
- var started = false
- var dragged = false
- var stopped = false
-
- var childConsumesOnPass: PointerEventPass? = null
-
- suspend fun AwaitPointerEventScope.childPointerInputScope() {
- awaitPointerEvent(PointerEventPass.Initial).also { initial ->
- // Check unconsumed: it should be always true
- assertThat(initial.changes.any { it.isConsumed }).isFalse()
-
- if (childConsumesOnPass == PointerEventPass.Initial) {
- initial.changes.first().consume()
- }
- }
-
- awaitPointerEvent(PointerEventPass.Main).also { main ->
- // Check unconsumed
- if (childConsumesOnPass != PointerEventPass.Initial) {
- assertThat(main.changes.any { it.isConsumed }).isFalse()
- }
-
- if (childConsumesOnPass == PointerEventPass.Main) {
- main.changes.first().consume()
- }
- }
- }
-
- var touchSlop = 0f
- rule.setContent {
- touchSlop = LocalViewConfiguration.current.touchSlop
- Box(
- Modifier.size(with(LocalDensity.current) { Size(size, size).toDpSize() })
- .nestedScrollDispatcher()
- .multiPointerDraggable(
- orientation = Orientation.Vertical,
- onDragStarted = { _, _ ->
- started = true
- SimpleDragController(
- onDrag = { dragged = true },
- onStop = { stopped = true },
- )
- },
- dispatcher = defaultDispatcher,
- )
- ) {
- Box(
- Modifier.pointerInput(Unit) {
- coroutineScope {
- awaitPointerEventScope {
- while (isActive) {
- childPointerInputScope()
- }
- }
- }
- }
- .fillMaxSize()
- )
- }
- }
-
- fun startDraggingDown() {
- rule.onRoot().performTouchInput {
- down(middle)
- moveBy(Offset(0f, touchSlop))
- }
- }
-
- fun continueDraggingDown() {
- rule.onRoot().performTouchInput { moveBy(Offset(0f, touchSlop)) }
- }
-
- childConsumesOnPass = PointerEventPass.Initial
-
- startDraggingDown()
- assertThat(started).isFalse()
- assertThat(dragged).isFalse()
- assertThat(stopped).isFalse()
-
- continueDraggingDown()
- assertThat(started).isFalse()
- assertThat(dragged).isFalse()
- assertThat(stopped).isFalse()
-
- childConsumesOnPass = PointerEventPass.Main
-
- continueDraggingDown()
- assertThat(started).isFalse()
- assertThat(dragged).isFalse()
- assertThat(stopped).isFalse()
-
- continueDraggingDown()
- assertThat(started).isFalse()
- assertThat(dragged).isFalse()
- assertThat(stopped).isFalse()
-
- childConsumesOnPass = null
-
- // Swipe down. This will be intercepted by multiPointerDraggable, it will wait touchSlop
- // before consuming it.
- continueDraggingDown()
- assertThat(started).isFalse()
- assertThat(dragged).isFalse()
- assertThat(stopped).isFalse()
-
- // Swipe down. This should both call onDragStarted() and onDragDelta().
- continueDraggingDown()
- assertThat(started).isTrue()
- assertThat(dragged).isTrue()
- assertThat(stopped).isFalse()
-
- childConsumesOnPass = PointerEventPass.Main
-
- continueDraggingDown()
- assertThat(stopped).isTrue()
-
- // Complete the gesture
- rule.onRoot().performTouchInput { up() }
- }
-
- @Test
- fun multiPointerDuringAnotherGestureWaitAConsumableEventAfterMainPass() {
- val size = 200f
- val middle = Offset(size / 2f, size / 2f)
-
- var verticalStarted = false
- var verticalDragged = false
- var verticalStopped = false
- var horizontalStarted = false
- var horizontalDragged = false
- var horizontalStopped = false
-
- var touchSlop = 0f
- rule.setContent {
- touchSlop = LocalViewConfiguration.current.touchSlop
- Box(
- Modifier.size(with(LocalDensity.current) { Size(size, size).toDpSize() })
- .nestedScrollDispatcher()
- .multiPointerDraggable(
- orientation = Orientation.Vertical,
- onDragStarted = { _, _ ->
- verticalStarted = true
- SimpleDragController(
- onDrag = { verticalDragged = true },
- onStop = { verticalStopped = true },
- )
- },
- dispatcher = defaultDispatcher,
- )
- .multiPointerDraggable(
- orientation = Orientation.Horizontal,
- onDragStarted = { _, _ ->
- horizontalStarted = true
- SimpleDragController(
- onDrag = { horizontalDragged = true },
- onStop = { horizontalStopped = true },
- )
- },
- dispatcher = defaultDispatcher,
- )
- )
- }
-
- fun startDraggingDown() {
- rule.onRoot().performTouchInput {
- down(middle)
- moveBy(Offset(0f, touchSlop))
- }
- }
-
- fun startDraggingRight() {
- rule.onRoot().performTouchInput {
- down(middle)
- moveBy(Offset(touchSlop, 0f))
- }
- }
-
- fun stopDragging() {
- rule.onRoot().performTouchInput { up() }
- }
-
- fun continueDown() {
- rule.onRoot().performTouchInput { moveBy(Offset(0f, touchSlop)) }
- }
-
- fun continueRight() {
- rule.onRoot().performTouchInput { moveBy(Offset(touchSlop, 0f)) }
- }
-
- startDraggingDown()
- assertThat(verticalStarted).isTrue()
- assertThat(verticalDragged).isTrue()
- assertThat(verticalStopped).isFalse()
-
- // Ignore right swipe, do not interrupt the dragging gesture.
- continueRight()
- assertThat(horizontalStarted).isFalse()
- assertThat(horizontalDragged).isFalse()
- assertThat(horizontalStopped).isFalse()
- assertThat(verticalStopped).isFalse()
-
- stopDragging()
- assertThat(verticalStopped).isTrue()
-
- verticalStarted = false
- verticalDragged = false
- verticalStopped = false
-
- startDraggingRight()
- assertThat(horizontalStarted).isTrue()
- assertThat(horizontalDragged).isTrue()
- assertThat(horizontalStopped).isFalse()
-
- // Ignore down swipe, do not interrupt the dragging gesture.
- continueDown()
- assertThat(verticalStarted).isFalse()
- assertThat(verticalDragged).isFalse()
- assertThat(verticalStopped).isFalse()
- assertThat(horizontalStopped).isFalse()
-
- stopDragging()
- assertThat(horizontalStopped).isTrue()
- }
-
- @Test
- fun multiPointerSwipeDetectorInteraction() {
- val size = 200f
- val middle = Offset(size / 2f, size / 2f)
-
- var started = false
-
- var capturedChange: PointerInputChange? = null
- var swipeConsume = false
-
- var touchSlop = 0f
- rule.setContent {
- touchSlop = LocalViewConfiguration.current.touchSlop
- Box(
- Modifier.size(with(LocalDensity.current) { Size(size, size).toDpSize() })
- .nestedScrollDispatcher()
- .multiPointerDraggable(
- orientation = Orientation.Vertical,
- swipeDetector =
- object : SwipeDetector {
- override fun detectSwipe(change: PointerInputChange): Boolean {
- capturedChange = change
- return swipeConsume
- }
- },
- onDragStarted = { _, _ ->
- started = true
- SimpleDragController(
- onDrag = { /* do nothing */ },
- onStop = { /* do nothing */ },
- )
- },
- dispatcher = defaultDispatcher,
- )
- ) {}
- }
-
- fun startDraggingDown() {
- rule.onRoot().performTouchInput {
- down(middle)
- moveBy(Offset(0f, touchSlop))
- }
- }
-
- fun dragDown() {
- rule.onRoot().performTouchInput { moveBy(Offset(0f, touchSlop)) }
- }
-
- startDraggingDown()
- assertThat(capturedChange).isNotNull()
- capturedChange = null
- assertThat(started).isFalse()
-
- swipeConsume = true
- // Drag in same direction
- dragDown()
- assertThat(capturedChange).isNotNull()
- capturedChange = null
-
- dragDown()
- assertThat(capturedChange).isNull()
-
- assertThat(started).isTrue()
- }
-
- @Test
- fun multiPointerSwipeDetectorInteractionZeroOffsetFromStartPosition() {
- val size = 200f
- val middle = Offset(size / 2f, size / 2f)
-
- var started = false
-
- var capturedChange: PointerInputChange? = null
- var swipeConsume = false
-
- var touchSlop = 0f
- rule.setContent {
- touchSlop = LocalViewConfiguration.current.touchSlop
- Box(
- Modifier.size(with(LocalDensity.current) { Size(size, size).toDpSize() })
- .nestedScrollDispatcher()
- .multiPointerDraggable(
- orientation = Orientation.Vertical,
- swipeDetector =
- object : SwipeDetector {
- override fun detectSwipe(change: PointerInputChange): Boolean {
- capturedChange = change
- return swipeConsume
- }
- },
- onDragStarted = { _, _ ->
- started = true
- SimpleDragController(
- onDrag = { /* do nothing */ },
- onStop = { /* do nothing */ },
- )
- },
- dispatcher = defaultDispatcher,
- )
- ) {}
- }
-
- fun startDraggingDown() {
- rule.onRoot().performTouchInput {
- down(middle)
- moveBy(Offset(0f, touchSlop))
- }
- }
-
- fun dragUp() {
- rule.onRoot().performTouchInput { moveBy(Offset(0f, -touchSlop)) }
- }
-
- startDraggingDown()
- assertThat(capturedChange).isNotNull()
- capturedChange = null
- assertThat(started).isFalse()
-
- swipeConsume = true
- // Drag in the opposite direction
- dragUp()
- assertThat(capturedChange).isNotNull()
- capturedChange = null
-
- dragUp()
- assertThat(capturedChange).isNull()
-
- assertThat(started).isTrue()
- }
-
- @Test
- fun multiPointerNestedScrollDispatcher() {
- val size = 200f
- val middle = Offset(size / 2f, size / 2f)
- var touchSlop = 0f
-
- var consumedOnPreScroll = 0f
-
- var availableOnPreScroll = Float.MIN_VALUE
- var availableOnPostScroll = Float.MIN_VALUE
- var availableOnPreFling = Float.MIN_VALUE
- var availableOnPostFling = Float.MIN_VALUE
-
- var consumedOnDrag = 0f
- var consumedOnDragStop = 0f
-
- val connection =
- object : NestedScrollConnection {
- override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
- availableOnPreScroll = available.y
- return Offset(0f, consumedOnPreScroll)
- }
-
- override fun onPostScroll(
- consumed: Offset,
- available: Offset,
- source: NestedScrollSource,
- ): Offset {
- availableOnPostScroll = available.y
- return Offset.Zero
- }
-
- override suspend fun onPreFling(available: Velocity): Velocity {
- availableOnPreFling = available.y
- return Velocity.Zero
- }
-
- override suspend fun onPostFling(
- consumed: Velocity,
- available: Velocity,
- ): Velocity {
- availableOnPostFling = available.y
- return Velocity.Zero
- }
- }
-
- rule.setContent {
- touchSlop = LocalViewConfiguration.current.touchSlop
- Box(
- Modifier.size(with(LocalDensity.current) { Size(size, size).toDpSize() })
- .nestedScroll(connection)
- .nestedScrollDispatcher()
- .multiPointerDraggable(
- orientation = Orientation.Vertical,
- onDragStarted = { _, _ ->
- SimpleDragController(
- onDrag = { consumedOnDrag = it },
- onStop = { consumedOnDragStop = it },
- )
- },
- dispatcher = defaultDispatcher,
- )
- )
- }
-
- fun startDrag() {
- rule.onRoot().performTouchInput {
- down(middle)
- moveBy(Offset(0f, touchSlop))
- }
- }
-
- fun continueDrag() {
- rule.onRoot().performTouchInput { moveBy(Offset(0f, touchSlop)) }
- }
-
- fun stopDrag() {
- rule.onRoot().performTouchInput { up() }
- }
-
- startDrag()
-
- continueDrag()
- assertThat(availableOnPreScroll).isEqualTo(touchSlop)
- assertThat(consumedOnDrag).isEqualTo(touchSlop)
- assertThat(availableOnPostScroll).isEqualTo(0f)
-
- // Parent node consumes half of the gesture
- consumedOnPreScroll = touchSlop / 2f
- continueDrag()
- assertThat(availableOnPreScroll).isEqualTo(touchSlop)
- assertThat(consumedOnDrag).isEqualTo(touchSlop / 2f)
- assertThat(availableOnPostScroll).isEqualTo(0f)
-
- // Parent node consumes the gesture
- consumedOnPreScroll = touchSlop
- continueDrag()
- assertThat(availableOnPreScroll).isEqualTo(touchSlop)
- assertThat(consumedOnDrag).isEqualTo(0f)
- assertThat(availableOnPostScroll).isEqualTo(0f)
-
- // Parent node can intercept the velocity on stop
- stopDrag()
- assertThat(availableOnPreFling).isEqualTo(consumedOnDragStop)
- assertThat(availableOnPostFling).isEqualTo(0f)
- }
-
- @Test
- fun multiPointerOnStopVelocity() {
- val size = 200f
- val middle = Offset(size / 2f, size / 2f)
-
- var stopped = false
- var lastVelocity = -1f
- var touchSlop = 0f
- var density: Density by Delegates.notNull()
- rule.setContent {
- touchSlop = LocalViewConfiguration.current.touchSlop
- density = LocalDensity.current
- Box(
- Modifier.size(with(density) { Size(size, size).toDpSize() })
- .nestedScrollDispatcher()
- .multiPointerDraggable(
- orientation = Orientation.Vertical,
- onDragStarted = { _, _ ->
- SimpleDragController(
- onDrag = { /* do nothing */ },
- onStop = {
- stopped = true
- lastVelocity = it
- },
- )
- },
- dispatcher = defaultDispatcher,
- )
- )
- }
-
- var eventMillis: Long by Delegates.notNull()
- rule.onRoot().performTouchInput { eventMillis = eventPeriodMillis }
-
- fun swipeGesture(block: TouchInjectionScope.() -> Unit) {
- stopped = false
- rule.onRoot().performTouchInput {
- down(middle)
- block()
- up()
- }
- assertThat(stopped).isEqualTo(true)
- }
-
- val shortDistance = touchSlop / 2f
- swipeGesture {
- moveBy(delta = Offset(0f, shortDistance), delayMillis = eventMillis)
- moveBy(delta = Offset(0f, shortDistance), delayMillis = eventMillis)
- }
- assertThat(lastVelocity).isGreaterThan(0f)
- assertThat(lastVelocity).isWithin(1f).of((shortDistance / eventMillis) * 1000f)
-
- val longDistance = touchSlop * 4f
- swipeGesture {
- moveBy(delta = Offset(0f, longDistance), delayMillis = eventMillis)
- moveBy(delta = Offset(0f, longDistance), delayMillis = eventMillis)
- }
- assertThat(lastVelocity).isGreaterThan(0f)
- assertThat(lastVelocity).isWithin(1f).of((longDistance / eventMillis) * 1000f)
-
- rule.onRoot().performTouchInput {
- down(pointerId = 0, position = middle)
- down(pointerId = 1, position = middle)
- moveBy(pointerId = 0, delta = Offset(0f, longDistance), delayMillis = eventMillis)
- moveBy(pointerId = 0, delta = Offset(0f, longDistance), delayMillis = eventMillis)
- // The velocity should be:
- // (longDistance / eventMillis) pixels/ms
-
- // 1 pointer left, the second one
- up(pointerId = 0)
-
- // After a few events the velocity should be:
- // (shortDistance / eventMillis) pixels/ms
- repeat(10) {
- moveBy(pointerId = 1, delta = Offset(0f, shortDistance), delayMillis = eventMillis)
- }
- up(pointerId = 1)
- }
- assertThat(lastVelocity).isGreaterThan(0f)
- assertThat(lastVelocity).isWithin(1f).of((shortDistance / eventMillis) * 1000f)
- }
-}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt
index bad4c6298e6b..93fa51654ca1 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt
@@ -547,7 +547,7 @@ class OverlayTest {
val sharedIntValueByContent = mutableMapOf<ContentKey, Int>()
@Composable
- fun SceneScope.animateContentInt(targetValue: Int) {
+ fun ContentScope.animateContentInt(targetValue: Int) {
val animatedValue = animateContentIntAsState(targetValue, sharedIntKey)
LaunchedEffect(animatedValue) {
try {
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
index 0355a30d5c73..e03608466dae 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
@@ -128,7 +128,7 @@ class SwipeToSceneTest {
mapOf(
Swipe.Down to SceneA,
Swipe.Down(pointerCount = 2) to SceneB,
- Swipe.Down(pointersType = PointerType.Mouse) to SceneD,
+ Swipe.Down(pointerType = PointerType.Mouse) to SceneD,
Swipe.Down(fromSource = Edge.Top) to SceneB,
Swipe.Right(fromSource = Edge.Left) to SceneB,
)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt
index 6db98a874787..8db7dbca2474 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt
@@ -19,6 +19,7 @@ package com.android.compose.animation.scene.subjects
import com.android.compose.animation.scene.OverlayKey
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.mechanics.GestureContext
import com.google.common.truth.Fact.simpleFact
import com.google.common.truth.FailureMetadata
import com.google.common.truth.Subject
@@ -98,6 +99,17 @@ private constructor(metadata: FailureMetadata, private val actual: TransitionSta
return actual as TransitionState.Transition.ReplaceOverlay
}
+ fun hasGestureContext(): GestureContext {
+ if (actual !is TransitionState.Transition) {
+ failWithActual(simpleFact("expected to be TransitionState.Transition"))
+ }
+
+ val gestureContext = ((actual as TransitionState.Transition).gestureContext)
+ check("transition.gestureContext").that(gestureContext).isNotNull()
+
+ return checkNotNull(gestureContext)
+ }
+
companion object {
fun transitionStates() = Factory { metadata, actual: TransitionState ->
TransitionStateSubject(metadata, actual)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestOverlayTransition.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestOverlayTransition.kt
index b9d01c2eaa3b..c22c19867dbb 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestOverlayTransition.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestOverlayTransition.kt
@@ -20,6 +20,7 @@ import com.android.compose.animation.scene.OverlayKey
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.content.state.TransitionState.Transition
+import com.android.mechanics.GestureContext
import kotlinx.coroutines.CompletableDeferred
/** A [Transition.ShowOrHideOverlay] for tests that will be finished once [finish] is called. */
@@ -84,6 +85,7 @@ fun transition(
override val isInitiatedByUserInput: Boolean = isInitiatedByUserInput
override val isUserInputOngoing: Boolean = isUserInputOngoing
+ override val gestureContext: GestureContext? = null
override fun freezeAndAnimateToCurrentState() {
if (onFreezeAndAnimate != null) {
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestReplaceOverlayTransition.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestReplaceOverlayTransition.kt
index 983c429aa58e..139dcd5d5114 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestReplaceOverlayTransition.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestReplaceOverlayTransition.kt
@@ -19,6 +19,7 @@ package com.android.compose.test
import com.android.compose.animation.scene.OverlayKey
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.content.state.TransitionState.Transition
+import com.android.mechanics.GestureContext
import kotlinx.coroutines.CompletableDeferred
/** A [Transition.ShowOrHideOverlay] for tests that will be finished once [finish] is called. */
@@ -81,6 +82,7 @@ fun transition(
override val isInitiatedByUserInput: Boolean = isInitiatedByUserInput
override val isUserInputOngoing: Boolean = isUserInputOngoing
+ override val gestureContext: GestureContext? = null
override fun freezeAndAnimateToCurrentState() {
if (onFreezeAndAnimate != null) {
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestSceneTransition.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestSceneTransition.kt
index d11951ee4b24..18cd57bb985f 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestSceneTransition.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/TestSceneTransition.kt
@@ -19,6 +19,7 @@ package com.android.compose.test
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.content.state.TransitionState.Transition
+import com.android.mechanics.GestureContext
import kotlinx.coroutines.CompletableDeferred
/** A [Transition.ChangeScene] for tests that will be finished once [finish] is called. */
@@ -54,6 +55,7 @@ fun transition(
isUserInputOngoing: Boolean = false,
onFreezeAndAnimate: ((TestSceneTransition) -> Unit)? = null,
replacedTransition: Transition? = null,
+ gestureContext: GestureContext? = null,
): TestSceneTransition {
return object : TestSceneTransition(from, to, replacedTransition) {
override val currentScene: SceneKey
@@ -76,6 +78,7 @@ fun transition(
override val isInitiatedByUserInput: Boolean = isInitiatedByUserInput
override val isUserInputOngoing: Boolean = isUserInputOngoing
+ override val gestureContext: GestureContext? = gestureContext
override fun freezeAndAnimateToCurrentState() {
if (onFreezeAndAnimate != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorLocation.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/SensorLocation.kt
index 2f2f3a35dbaa..552679224bca 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorLocation.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/SensorLocation.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.biometrics.shared.model
+package com.android.systemui.shared.customization.data
/**
* Provides current sensor location information in the current screen resolution [scale].
@@ -26,18 +26,40 @@ data class SensorLocation(
private val naturalCenterX: Int,
private val naturalCenterY: Int,
private val naturalRadius: Int,
- private val scale: Float = 1f
+ private val scale: Float = 1f,
) {
val centerX: Float
get() {
return naturalCenterX * scale
}
+
val centerY: Float
get() {
return naturalCenterY * scale
}
+
val radius: Float
get() {
return naturalRadius * scale
}
+
+ fun encode(): String {
+ return floatArrayOf(
+ naturalCenterX.toFloat(),
+ naturalCenterY.toFloat(),
+ naturalRadius.toFloat(),
+ scale,
+ )
+ .joinToString(DELIMITER)
+ }
+
+ companion object {
+
+ private const val DELIMITER: String = ","
+
+ fun decode(encoded: String): SensorLocation {
+ val array = encoded.split(DELIMITER).map { it.toFloat() }.toFloatArray()
+ return SensorLocation(array[0].toInt(), array[1].toInt(), array[2].toInt(), array[3])
+ }
+ }
}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderClient.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderClient.kt
index 48af2d9f5542..caa6636bde03 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderClient.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderClient.kt
@@ -80,13 +80,6 @@ interface CustomizationProviderClient {
fun observeFlags(): Flow<List<Flag>>
/**
- * Returns [Flow] for observing the variables from the System UI.
- *
- * @see [queryRuntimeValues]
- */
- fun observeRuntimeValues(): Flow<Bundle>
-
- /**
* Returns all available affordances supported by the device, regardless of current slot
* placement.
*/
@@ -291,6 +284,9 @@ class CustomizationProviderClientImpl(
Contract.RuntimeValuesTable.KEY_IS_SHADE_LAYOUT_WIDE -> {
putBoolean(name, cursor.getInt(valueColumnIndex) == 1)
}
+ Contract.RuntimeValuesTable.KEY_UDFPS_LOCATION -> {
+ putString(name, cursor.getString(valueColumnIndex))
+ }
}
}
}
@@ -307,10 +303,6 @@ class CustomizationProviderClientImpl(
return observeUri(Contract.FlagsTable.URI).map { queryFlags() }
}
- override fun observeRuntimeValues(): Flow<Bundle> {
- return observeUri(Contract.RuntimeValuesTable.URI).map { queryRuntimeValues() }
- }
-
override suspend fun queryAffordances(): List<CustomizationProviderClient.Affordance> {
return withContext(backgroundDispatcher) {
context.contentResolver
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
index cb167eddcea9..2934f070b05f 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
@@ -19,6 +19,7 @@ package com.android.systemui.shared.customization.data.content
import android.content.ContentResolver
import android.net.Uri
+import com.android.systemui.shared.customization.data.SensorLocation
/** Contract definitions for querying content about keyguard quick affordances. */
object CustomizationProviderContract {
@@ -213,6 +214,11 @@ object CustomizationProviderContract {
* be as wide as the entire screen.
*/
const val KEY_IS_SHADE_LAYOUT_WIDE = "is_shade_layout_wide"
+ /**
+ * This key corresponds to a String value, representing the string form of [SensorLocation],
+ * which contains the information of the UDFPS location.
+ */
+ const val KEY_UDFPS_LOCATION = "udfps_location"
object Columns {
/** String. Unique ID for the value. */
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/FakeCustomizationProviderClient.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/FakeCustomizationProviderClient.kt
index 47c5bda93c0e..70d17820a12c 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/FakeCustomizationProviderClient.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/FakeCustomizationProviderClient.kt
@@ -108,10 +108,6 @@ class FakeCustomizationProviderClient(
return flags.asStateFlow()
}
- override fun observeRuntimeValues(): Flow<Bundle> {
- return runtimeValues.asStateFlow()
- }
-
override suspend fun queryAffordances(): List<CustomizationProviderClient.Affordance> {
return affordances.value
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
index 4d1660e71c0a..e26e19d27417 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
@@ -79,8 +79,6 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase {
@Mock
private LatencyTracker mLatencyTracker;
@Mock
- private LiftToActivateListener mLiftToactivateListener;
- @Mock
private EmergencyButtonController mEmergencyButtonController;
private FalsingCollector mFalsingCollector = new FalsingCollectorFake();
@Mock
@@ -122,7 +120,7 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase {
mSetFlagsRule.enableFlags(com.android.systemui.Flags.FLAG_REVAMPED_BOUNCER_MESSAGES);
mKeyguardPinViewController = new KeyguardPinBasedInputViewController(mPinBasedInputView,
mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
- mKeyguardMessageAreaControllerFactory, mLatencyTracker, mLiftToactivateListener,
+ mKeyguardMessageAreaControllerFactory, mLatencyTracker,
mEmergencyButtonController, mFalsingCollector, featureFlags,
mSelectedUserInteractor, keyguardKeyboardInteractor, mBouncerHapticPlayer,
mUserActivityNotifier) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
index 4d2a6d9bd57a..142a2868ec14 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
@@ -90,8 +90,6 @@ class KeyguardPinViewControllerTest : SysuiTestCase() {
@Mock private lateinit var mLatencyTracker: LatencyTracker
- @Mock private lateinit var liftToActivateListener: LiftToActivateListener
-
@Mock private val mEmergencyButtonController: EmergencyButtonController? = null
private val falsingCollector: FalsingCollector = FalsingCollectorFake()
private val keyguardKeyboardInteractor = KeyguardKeyboardInteractor(FakeKeyboardRepository())
@@ -147,7 +145,6 @@ class KeyguardPinViewControllerTest : SysuiTestCase() {
mKeyguardSecurityCallback,
keyguardMessageAreaControllerFactory,
mLatencyTracker,
- liftToActivateListener,
mEmergencyButtonController,
falsingCollector,
postureController,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
index 9cd52153eff6..c751a7db51dc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
@@ -63,7 +63,6 @@ class KeyguardSimPinViewControllerTest : SysuiTestCase() {
@Mock private lateinit var keyguardSecurityCallback: KeyguardSecurityCallback
@Mock private lateinit var messageAreaControllerFactory: KeyguardMessageAreaController.Factory
@Mock private lateinit var latencyTracker: LatencyTracker
- @Mock private lateinit var liftToActivateListener: LiftToActivateListener
@Mock private lateinit var telephonyManager: TelephonyManager
@Mock private lateinit var falsingCollector: FalsingCollector
@Mock private lateinit var emergencyButtonController: EmergencyButtonController
@@ -100,7 +99,6 @@ class KeyguardSimPinViewControllerTest : SysuiTestCase() {
keyguardSecurityCallback,
messageAreaControllerFactory,
latencyTracker,
- liftToActivateListener,
telephonyManager,
falsingCollector,
emergencyButtonController,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
index 3c229975eef5..c34682551eda 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
@@ -57,7 +57,6 @@ class KeyguardSimPukViewControllerTest : SysuiTestCase() {
@Mock private lateinit var keyguardSecurityCallback: KeyguardSecurityCallback
@Mock private lateinit var messageAreaControllerFactory: KeyguardMessageAreaController.Factory
@Mock private lateinit var latencyTracker: LatencyTracker
- @Mock private lateinit var liftToActivateListener: LiftToActivateListener
@Mock private lateinit var telephonyManager: TelephonyManager
@Mock private lateinit var falsingCollector: FalsingCollector
@Mock private lateinit var emergencyButtonController: EmergencyButtonController
@@ -95,7 +94,6 @@ class KeyguardSimPukViewControllerTest : SysuiTestCase() {
keyguardSecurityCallback,
messageAreaControllerFactory,
latencyTracker,
- liftToActivateListener,
telephonyManager,
falsingCollector,
emergencyButtonController,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
index 56a97bb34172..fff6def52803 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import android.graphics.PointF;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.testing.TestableLooper;
@@ -210,7 +211,7 @@ public class MenuListViewTouchHandlerTest extends SysuiTestCase {
mTouchHandler.onInterceptTouchEvent(mStubListView, stubMoveEvent);
mTouchHandler.onInterceptTouchEvent(mStubListView, stubUpEvent);
- verify(mMenuAnimationController).flingMenuThenSpringToEdge(anyFloat(), anyFloat(),
+ verify(mMenuAnimationController).flingMenuThenSpringToEdge(any(PointF.class), anyFloat(),
anyFloat());
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
index 5ff7bd063427..737170f6a665 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
@@ -18,17 +18,25 @@ package com.android.systemui.accessibility.floatingmenu;
import static android.app.UiModeManager.MODE_NIGHT_YES;
+import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.app.UiModeManager;
+import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
+import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.testing.TestableLooper;
import android.view.WindowManager;
@@ -37,6 +45,8 @@ import android.view.accessibility.AccessibilityManager;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.internal.accessibility.common.ShortcutConstants;
+import com.android.internal.accessibility.dialog.AccessibilityTarget;
import com.android.settingslib.bluetooth.HearingAidDeviceManager;
import com.android.systemui.Flags;
import com.android.systemui.Prefs;
@@ -54,6 +64,9 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
+import java.util.ArrayList;
+import java.util.List;
+
/** Tests for {@link MenuView}. */
@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -63,17 +76,24 @@ public class MenuViewTest extends SysuiTestCase {
private int mNightMode;
private UiModeManager mUiModeManager;
private MenuView mMenuView;
+ private MenuView mMenuViewSpy;
private String mLastPosition;
private MenuViewAppearance mStubMenuViewAppearance;
+ private MenuViewModel mMenuViewModel;
+ private final List<String> mShortcutTargets = new ArrayList<>();
@Rule
public MockitoRule mockito = MockitoJUnit.rule();
@Mock
private AccessibilityManager mAccessibilityManager;
+
@Mock
private HearingAidDeviceManager mHearingAidDeviceManager;
+ @Mock
+ private MenuView.OnTargetFeaturesChangeListener mOnTargetFeaturesChangeListener;
+
private SysuiTestableContext mSpyContext;
@Before
@@ -91,22 +111,38 @@ public class MenuViewTest extends SysuiTestCase {
mSpyContext = spy(mContext);
doNothing().when(mSpyContext).startActivity(any());
+ mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE, mAccessibilityManager);
+ mShortcutTargets.add(MAGNIFICATION_CONTROLLER_NAME);
+ doReturn(mShortcutTargets)
+ .when(mAccessibilityManager)
+ .getAccessibilityShortcutTargets(anyInt());
+
final SecureSettings secureSettings = TestUtils.mockSecureSettings(mContext);
- final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager,
- secureSettings, mHearingAidDeviceManager);
+ mMenuViewModel =
+ new MenuViewModel(
+ mContext, mAccessibilityManager, secureSettings, mHearingAidDeviceManager);
final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
mStubMenuViewAppearance = new MenuViewAppearance(mSpyContext, stubWindowManager);
- mMenuView = spy(new MenuView(mSpyContext, stubMenuViewModel, mStubMenuViewAppearance,
- secureSettings));
+ mMenuView =
+ new MenuView(mSpyContext, mMenuViewModel, mStubMenuViewAppearance, secureSettings);
+ mMenuView.setOnTargetFeaturesChangeListener(mOnTargetFeaturesChangeListener);
mLastPosition = Prefs.getString(mSpyContext,
Prefs.Key.ACCESSIBILITY_FLOATING_MENU_POSITION, /* defaultValue= */ null);
+
+ mMenuViewSpy =
+ spy(
+ new MenuView(
+ mSpyContext,
+ mMenuViewModel,
+ mStubMenuViewAppearance,
+ secureSettings));
}
@Test
public void onConfigurationChanged_updateViewModel() {
- mMenuView.onConfigurationChanged(/* newConfig= */ null);
+ mMenuViewSpy.onConfigurationChanged(/* newConfig= */ null);
- verify(mMenuView).loadLayoutResources();
+ verify(mMenuViewSpy).loadLayoutResources();
}
@Test
@@ -179,6 +215,75 @@ public class MenuViewTest extends SysuiTestCase {
assertThat(radiiAnimator.isStarted()).isTrue();
}
+ @Test
+ @DisableFlags(Flags.FLAG_FLOATING_MENU_NOTIFY_TARGETS_CHANGED_ON_STRICT_DIFF)
+ public void onTargetFeaturesChanged_listenerCalled_flagDisabled() {
+ // Call show() to start observing the target features change listener.
+ mMenuView.show();
+
+ // The target features change listener should be called when the observer is added.
+ verify(mOnTargetFeaturesChangeListener, times(1)).onChange(any());
+
+ // When the target features list changes, the listener should be called.
+ mMenuViewModel.onTargetFeaturesChanged(
+ List.of(
+ new TestAccessibilityTarget(mContext, 123),
+ new TestAccessibilityTarget(mContext, 456)));
+ verify(mOnTargetFeaturesChangeListener, times(2)).onChange(any());
+
+ // Double check that when the target features list changes, the listener should be called.
+ List<AccessibilityTarget> newFeaturesList =
+ List.of(
+ new TestAccessibilityTarget(mContext, 123),
+ new TestAccessibilityTarget(mContext, 789),
+ new TestAccessibilityTarget(mContext, 456));
+ mMenuViewModel.onTargetFeaturesChanged(newFeaturesList);
+ verify(mOnTargetFeaturesChangeListener, times(3)).onChange(any());
+
+ // When the target features list doesn't change, the listener will still be called.
+ mMenuViewModel.onTargetFeaturesChanged(newFeaturesList);
+ verify(mOnTargetFeaturesChangeListener, times(4)).onChange(any());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_FLOATING_MENU_NOTIFY_TARGETS_CHANGED_ON_STRICT_DIFF)
+ public void onTargetFeaturesChanged_listenerCalled_flagEnabled() {
+ // Call show() to start observing the target features change listener.
+ mMenuView.show();
+
+ // The target features change listener should be called when the observer is added.
+ verify(mOnTargetFeaturesChangeListener, times(1)).onChange(any());
+
+ // When the target features list changes, the listener should be called.
+ mMenuViewModel.onTargetFeaturesChanged(
+ List.of(
+ new TestAccessibilityTarget(mContext, 123),
+ new TestAccessibilityTarget(mContext, 456)));
+ verify(mOnTargetFeaturesChangeListener, times(2)).onChange(any());
+
+ // Double check that when the target features list changes, the listener should be called.
+ List<AccessibilityTarget> newFeaturesList =
+ List.of(
+ new TestAccessibilityTarget(mContext, 123),
+ new TestAccessibilityTarget(mContext, 789),
+ new TestAccessibilityTarget(mContext, 456));
+ mMenuViewModel.onTargetFeaturesChanged(newFeaturesList);
+ verify(mOnTargetFeaturesChangeListener, times(3)).onChange(any());
+
+ // When the target features list doesn't change, the listener should not be called again.
+ mMenuViewModel.onTargetFeaturesChanged(newFeaturesList);
+ verify(mOnTargetFeaturesChangeListener, times(3)).onChange(any());
+
+ // When the target features list changes order (but the UIDs of the targets don't change),
+ // the listener should be called.
+ mMenuViewModel.onTargetFeaturesChanged(
+ List.of(
+ new TestAccessibilityTarget(mContext, 789),
+ new TestAccessibilityTarget(mContext, 123),
+ new TestAccessibilityTarget(mContext, 456)));
+ verify(mOnTargetFeaturesChangeListener, times(4)).onChange(any());
+ }
+
private InstantInsetLayerDrawable getMenuViewInsetLayer() {
return (InstantInsetLayerDrawable) mMenuView.getBackground();
}
@@ -196,6 +301,23 @@ public class MenuViewTest extends SysuiTestCase {
return radiiAnimator;
}
+ /** Simplified AccessibilityTarget for testing MenuView. */
+ private static class TestAccessibilityTarget extends AccessibilityTarget {
+ TestAccessibilityTarget(Context context, int uid) {
+ // Set fields unused by tests to defaults that allow test compilation.
+ super(
+ context,
+ ShortcutConstants.UserShortcutType.SOFTWARE,
+ 0,
+ false,
+ MAGNIFICATION_COMPONENT_NAME.flattenToString(),
+ uid,
+ null,
+ null,
+ null);
+ }
+ }
+
@After
public void tearDown() throws Exception {
mUiModeManager.setNightMode(mNightMode);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
index 43d0d69c428f..e4539b75f317 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
@@ -66,7 +66,6 @@ import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.bluetooth.VolumeControlProfile;
-import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogTransitionAnimator;
import com.android.systemui.bluetooth.qsdialog.DeviceItem;
@@ -227,7 +226,6 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
}
@Test
- @EnableFlags(Flags.FLAG_HEARING_DEVICES_DIALOG_RELATED_TOOLS)
public void showDialog_noLiveCaption_noRelatedToolsInConfig_relatedToolLayoutGone() {
mContext.getOrCreateTestableResources().addOverride(
R.array.config_quickSettingsHearingDevicesRelatedToolName, new String[]{});
@@ -239,7 +237,6 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
}
@Test
- @EnableFlags(Flags.FLAG_HEARING_DEVICES_DIALOG_RELATED_TOOLS)
public void showDialog_hasLiveCaption_noRelatedToolsInConfig_showOneRelatedTool() {
when(mPackageManager.queryIntentActivities(
eq(LIVE_CAPTION_INTENT), anyInt())).thenReturn(
@@ -254,7 +251,6 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
}
@Test
- @EnableFlags(Flags.FLAG_HEARING_DEVICES_DIALOG_RELATED_TOOLS)
public void showDialog_hasLiveCaption_oneRelatedToolInConfig_showTwoRelatedTools()
throws PackageManager.NameNotFoundException {
when(mPackageManager.queryIntentActivities(eq(LIVE_CAPTION_INTENT), anyInt()))
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepositoryTest.kt
new file mode 100644
index 000000000000..fbb0fee2419c
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepositoryTest.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.bouncer.data.repository
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.time.SystemClock
+import com.google.common.truth.Truth.assertThat
+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
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class KeyguardBouncerRepositoryTest : SysuiTestCase() {
+
+ @Mock private lateinit var systemClock: SystemClock
+ @Mock private lateinit var bouncerLogger: TableLogBuffer
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+
+ lateinit var underTest: KeyguardBouncerRepository
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ underTest =
+ object :
+ KeyguardBouncerRepositoryImpl(
+ systemClock,
+ testScope.backgroundScope,
+ bouncerLogger,
+ ) {
+ override fun isDebuggable(): Boolean = true
+ }
+ }
+
+ @Test
+ fun changingFlowValueTriggersLogging() =
+ testScope.runTest {
+ underTest.setPrimaryShow(true)
+ runCurrent()
+ Mockito.verify(bouncerLogger)
+ .logChange(eq(""), eq("PrimaryBouncerShow"), value = eq(false), any())
+ }
+
+ @Test
+ fun primaryStartDisappearAnimation() =
+ testScope.runTest {
+ assertThat(underTest.isPrimaryBouncerStartingDisappearAnimation()).isFalse()
+
+ underTest.setPrimaryStartDisappearAnimation(Runnable {})
+ assertThat(underTest.isPrimaryBouncerStartingDisappearAnimation()).isTrue()
+
+ underTest.setPrimaryStartDisappearAnimation(null)
+ assertThat(underTest.isPrimaryBouncerStartingDisappearAnimation()).isFalse()
+
+ val disappearFlow by collectValues(underTest.primaryBouncerStartingDisappearAnimation)
+ underTest.setPrimaryStartDisappearAnimation(null)
+ assertThat(disappearFlow[0]).isNull()
+
+ // Now issue two in a row to make sure one is not dropped
+ underTest.setPrimaryStartDisappearAnimation(Runnable {})
+ underTest.setPrimaryStartDisappearAnimation(null)
+ assertThat(disappearFlow[1]).isNotNull()
+ assertThat(disappearFlow[2]).isNull()
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
index d5e1fae215c7..c1feca29906a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
@@ -105,7 +105,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
mSelectedUserInteractor,
faceAuthInteractor,
)
- whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null)
+ whenever(repository.isPrimaryBouncerStartingDisappearAnimation()).thenReturn(false)
whenever(repository.primaryBouncerShow.value).thenReturn(false)
whenever(bouncerView.delegate).thenReturn(bouncerViewDelegate)
resources = context.orCreateTestableResources
@@ -199,7 +199,6 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
@Test
fun testExpansion_fullyShown() {
whenever(repository.panelExpansionAmount.value).thenReturn(0.5f)
- whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null)
underTest.setPanelExpansion(EXPANSION_VISIBLE)
verify(falsingCollector).onBouncerShown()
verify(mPrimaryBouncerCallbackInteractor).dispatchFullyShown()
@@ -208,7 +207,6 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
@Test
fun testExpansion_fullyHidden() {
whenever(repository.panelExpansionAmount.value).thenReturn(0.5f)
- whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null)
underTest.setPanelExpansion(EXPANSION_HIDDEN)
verify(repository).setPrimaryShow(false)
verify(falsingCollector).onBouncerHidden()
@@ -307,7 +305,6 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
fun testIsFullShowing() {
whenever(repository.primaryBouncerShow.value).thenReturn(true)
whenever(repository.panelExpansionAmount.value).thenReturn(EXPANSION_VISIBLE)
- whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null)
assertThat(underTest.isFullyShowing()).isTrue()
whenever(repository.primaryBouncerShow.value).thenReturn(false)
assertThat(underTest.isFullyShowing()).isFalse()
@@ -333,9 +330,9 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
@Test
fun testIsAnimatingAway() {
- whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(Runnable {})
+ whenever(repository.isPrimaryBouncerStartingDisappearAnimation()).thenReturn(true)
assertThat(underTest.isAnimatingAway()).isTrue()
- whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null)
+ whenever(repository.isPrimaryBouncerStartingDisappearAnimation()).thenReturn(false)
assertThat(underTest.isAnimatingAway()).isFalse()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/composable/BouncerPredictiveBackTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/composable/BouncerPredictiveBackTest.kt
index a65415509d38..a6ed37ead7ae 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/composable/BouncerPredictiveBackTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/composable/BouncerPredictiveBackTest.kt
@@ -37,10 +37,10 @@ import androidx.compose.ui.semantics.SemanticsNode
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.Scale
import com.android.compose.animation.scene.SceneKey
-import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.isElement
@@ -270,7 +270,7 @@ class BouncerPredictiveBackTest : SysuiTestCase() {
override val userActions: Flow<Map<UserAction, UserActionResult>> = flowOf()
@Composable
- override fun SceneScope.Content(modifier: Modifier) {
+ override fun ContentScope.Content(modifier: Modifier) {
Box(modifier = modifier, contentAlignment = Alignment.Center) {
Text(text = "Fake Lockscreen")
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/ClipboardImageLoaderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/ClipboardImageLoaderTest.kt
index 791f1f2e1f26..6fdeb2b8ebb0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/ClipboardImageLoaderTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/ClipboardImageLoaderTest.kt
@@ -17,14 +17,17 @@ package com.android.systemui.clipboardoverlay
import android.content.ContentResolver
import android.content.Context
+import android.content.pm.UserInfo
import android.net.Uri
+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.FLAG_CLIPBOARD_OVERLAY_MULTIUSER
import com.android.systemui.SysuiTestCase
-import com.android.systemui.util.mockito.whenever
+import com.android.systemui.settings.FakeUserTracker
import java.io.IOException
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertNull
@@ -36,44 +39,90 @@ import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.whenever
@SmallTest
-@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
class ClipboardImageLoaderTest : SysuiTestCase() {
@Mock private lateinit var mockContext: Context
@Mock private lateinit var mockContentResolver: ContentResolver
+ @Mock private lateinit var mockSecondaryContentResolver: ContentResolver
private lateinit var clipboardImageLoader: ClipboardImageLoader
+ private var fakeUserTracker: FakeUserTracker =
+ FakeUserTracker(userContentResolverProvider = { mockContentResolver })
+
+ private val userInfos = listOf(UserInfo(0, "system", 0), UserInfo(50, "secondary", 0))
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
+
+ fakeUserTracker.set(userInfos, 0)
}
@Test
@Throws(IOException::class)
+ @DisableFlags(FLAG_CLIPBOARD_OVERLAY_MULTIUSER)
+ fun test_imageLoadSuccess_legacy() = runTest {
+ val testDispatcher = StandardTestDispatcher(this.testScheduler)
+ fakeUserTracker =
+ FakeUserTracker(userContentResolverProvider = { mockSecondaryContentResolver })
+ fakeUserTracker.set(userInfos, 1)
+
+ clipboardImageLoader =
+ ClipboardImageLoader(
+ mockContext,
+ fakeUserTracker,
+ testDispatcher,
+ CoroutineScope(testDispatcher),
+ )
+ val testUri = Uri.parse("testUri")
+ whenever<ContentResolver?>(mockContext.contentResolver)
+ .thenReturn(mockSecondaryContentResolver)
+ whenever(mockContext.resources).thenReturn(context.resources)
+
+ clipboardImageLoader.load(testUri)
+
+ verify(mockSecondaryContentResolver).loadThumbnail(eq(testUri), any(), any())
+ }
+
+ @Test
+ @Throws(IOException::class)
+ @EnableFlags(FLAG_CLIPBOARD_OVERLAY_MULTIUSER)
fun test_imageLoadSuccess() = runTest {
val testDispatcher = StandardTestDispatcher(this.testScheduler)
+ fakeUserTracker =
+ FakeUserTracker(userContentResolverProvider = { mockSecondaryContentResolver })
+ fakeUserTracker.set(userInfos, 1)
+
clipboardImageLoader =
- ClipboardImageLoader(mockContext, testDispatcher, CoroutineScope(testDispatcher))
+ ClipboardImageLoader(
+ mockContext,
+ fakeUserTracker,
+ testDispatcher,
+ CoroutineScope(testDispatcher),
+ )
val testUri = Uri.parse("testUri")
- whenever(mockContext.contentResolver).thenReturn(mockContentResolver)
whenever(mockContext.resources).thenReturn(context.resources)
clipboardImageLoader.load(testUri)
- verify(mockContentResolver).loadThumbnail(eq(testUri), any(), any())
+ verify(mockSecondaryContentResolver).loadThumbnail(eq(testUri), any(), any())
}
- @OptIn(ExperimentalCoroutinesApi::class)
@Test
@Throws(IOException::class)
fun test_imageLoadFailure() = runTest {
val testDispatcher = StandardTestDispatcher(this.testScheduler)
clipboardImageLoader =
- ClipboardImageLoader(mockContext, testDispatcher, CoroutineScope(testDispatcher))
+ ClipboardImageLoader(
+ mockContext,
+ fakeUserTracker,
+ testDispatcher,
+ CoroutineScope(testDispatcher),
+ )
val testUri = Uri.parse("testUri")
whenever(mockContext.contentResolver).thenReturn(mockContentResolver)
whenever(mockContext.resources).thenReturn(context.resources)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalUserActionsViewModelTest.kt
index ca7e2032be93..26859b6e10f8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalUserActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalUserActionsViewModelTest.kt
@@ -190,11 +190,8 @@ class CommunalUserActionsViewModelTest : SysuiTestCase() {
lockDevice()
}
- if (shadeMode == ShadeMode.Dual) {
- assertThat(DualShade.isEnabled).isTrue()
- } else {
- assertThat(DualShade.isEnabled).isFalse()
- kosmos.fakeShadeRepository.setShadeLayoutWide(shadeMode == ShadeMode.Split)
+ if (shadeMode !is ShadeMode.Dual) {
+ kosmos.fakeShadeRepository.setShadeLayoutWide(shadeMode is ShadeMode.Split)
}
runCurrent()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorTest.kt
index 47cba0723804..030233625027 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorTest.kt
@@ -367,8 +367,6 @@ class DeviceUnlockedInteractorTest : SysuiTestCase() {
DeviceEntryRestrictionReason.DeviceNotUnlockedSinceReboot,
LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST to
DeviceEntryRestrictionReason.AdaptiveAuthRequest,
- LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT to
- DeviceEntryRestrictionReason.BouncerLockedOut,
LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to
DeviceEntryRestrictionReason.SecurityTimeout,
LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to
@@ -403,8 +401,6 @@ class DeviceUnlockedInteractorTest : SysuiTestCase() {
DeviceEntryRestrictionReason.DeviceNotUnlockedSinceReboot,
LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST to
DeviceEntryRestrictionReason.AdaptiveAuthRequest,
- LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT to
- DeviceEntryRestrictionReason.BouncerLockedOut,
LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to
DeviceEntryRestrictionReason.SecurityTimeout,
LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to
@@ -440,8 +436,6 @@ class DeviceUnlockedInteractorTest : SysuiTestCase() {
DeviceEntryRestrictionReason.DeviceNotUnlockedSinceReboot,
LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST to
DeviceEntryRestrictionReason.AdaptiveAuthRequest,
- LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT to
- DeviceEntryRestrictionReason.BouncerLockedOut,
LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to
DeviceEntryRestrictionReason.SecurityTimeout,
LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt
index d6daa794c45b..e19ea365fa1f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt
@@ -316,11 +316,8 @@ class DreamUserActionsViewModelTest : SysuiTestCase() {
lockDevice()
}
- if (shadeMode == ShadeMode.Dual) {
- assertThat(DualShade.isEnabled).isTrue()
- } else {
- assertThat(DualShade.isEnabled).isFalse()
- kosmos.fakeShadeRepository.setShadeLayoutWide(shadeMode == ShadeMode.Split)
+ if (shadeMode !is ShadeMode.Dual) {
+ kosmos.fakeShadeRepository.setShadeLayoutWide(shadeMode is ShadeMode.Split)
}
runCurrent()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
index 605a5d261424..bafabe07d370 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
@@ -22,6 +22,7 @@ import android.platform.test.annotations.RequiresFlagsEnabled
import android.platform.test.flag.junit.CheckFlagsRule
import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.view.IRemoteAnimationFinishedCallback
+import android.view.RemoteAnimationTarget
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -39,11 +40,11 @@ import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito.anyInt
-import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.any
+import org.mockito.kotlin.doAnswer
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
@@ -230,12 +231,15 @@ class WindowManagerLockscreenVisibilityManagerTest : SysuiTestCase() {
@Test
fun remoteAnimationInstantlyFinished_ifDismissTransitionNotStarted() {
val mockedCallback = mock<IRemoteAnimationFinishedCallback>()
- whenever(keyguardDismissTransitionInteractor.startDismissKeyguardTransition(any()))
- .thenReturn(false)
+
+ // Call the onAlreadyGone callback immediately.
+ doAnswer { invocation -> (invocation.getArgument(1) as (() -> Unit)).invoke() }
+ .whenever(keyguardDismissTransitionInteractor)
+ .startDismissKeyguardTransition(any(), any())
underTest.onKeyguardGoingAwayRemoteAnimationStart(
transit = 0,
- apps = emptyArray(),
+ apps = arrayOf(mock<RemoteAnimationTarget>()),
wallpapers = emptyArray(),
nonApps = emptyArray(),
finishedCallback = mockedCallback,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSColumnsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSColumnsRepositoryTest.kt
index ec0773f79328..5a350435002f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSColumnsRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSColumnsRepositoryTest.kt
@@ -24,7 +24,6 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testCase
import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
-import com.android.systemui.shade.data.repository.fakeShadeRepository
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
@@ -35,7 +34,17 @@ import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
class QSColumnsRepositoryTest : SysuiTestCase() {
- private val kosmos = testKosmos()
+ private val kosmos =
+ testKosmos().apply {
+ testCase.context.orCreateTestableResources.addOverride(
+ R.integer.quick_settings_dual_shade_num_columns,
+ 2,
+ )
+ testCase.context.orCreateTestableResources.addOverride(
+ R.integer.quick_settings_split_shade_num_columns,
+ 3,
+ )
+ }
private lateinit var underTest: QSColumnsRepository
@Before
@@ -63,7 +72,7 @@ class QSColumnsRepositoryTest : SysuiTestCase() {
testScope.runTest {
val latest by collectLastValue(underTest.dualShadeColumns)
- assertThat(latest).isEqualTo(4)
+ assertThat(latest).isEqualTo(2)
}
}
@@ -72,9 +81,8 @@ class QSColumnsRepositoryTest : SysuiTestCase() {
with(kosmos) {
testScope.runTest {
val latest by collectLastValue(underTest.splitShadeColumns)
- fakeShadeRepository.setShadeLayoutWide(true)
- assertThat(latest).isEqualTo(4)
+ assertThat(latest).isEqualTo(3)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/A11yShortcutAutoAddableListTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/A11yShortcutAutoAddableListTest.kt
index 16f30feb7e3b..9c630ebb0ad2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/A11yShortcutAutoAddableListTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/A11yShortcutAutoAddableListTest.kt
@@ -17,9 +17,6 @@
package com.android.systemui.qs.pipeline.domain.autoaddable
import android.content.ComponentName
-import android.platform.test.annotations.DisableFlags
-import android.platform.test.annotations.EnableFlags
-import android.view.accessibility.Flags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.accessibility.AccessibilityShortcutController
@@ -43,44 +40,35 @@ class A11yShortcutAutoAddableListTest : SysuiTestCase() {
object : A11yShortcutAutoAddable.Factory {
override fun create(
spec: TileSpec,
- componentName: ComponentName
+ componentName: ComponentName,
): A11yShortcutAutoAddable {
return A11yShortcutAutoAddable(mock(), mock(), spec, componentName)
}
}
@Test
- @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
- fun getA11yShortcutAutoAddables_withA11yQsShortcutFlagOff_emptyResult() {
- val autoAddables = A11yShortcutAutoAddableList.getA11yShortcutAutoAddables(factory)
-
- assertThat(autoAddables).isEmpty()
- }
-
- @Test
- @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
- fun getA11yShortcutAutoAddables_withA11yQsShortcutFlagOn_correctAutoAddables() {
+ fun getA11yShortcutAutoAddables_correctAutoAddables() {
val expected =
setOf(
factory.create(
TileSpec.create(ColorCorrectionTile.TILE_SPEC),
- AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME
+ AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME,
),
factory.create(
TileSpec.create(ColorInversionTile.TILE_SPEC),
- AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME
+ AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME,
),
factory.create(
TileSpec.create(OneHandedModeTile.TILE_SPEC),
- AccessibilityShortcutController.ONE_HANDED_COMPONENT_NAME
+ AccessibilityShortcutController.ONE_HANDED_COMPONENT_NAME,
),
factory.create(
TileSpec.create(ReduceBrightColorsTile.TILE_SPEC),
- AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_COMPONENT_NAME
+ AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_COMPONENT_NAME,
),
factory.create(
TileSpec.create(HearingDevicesTile.TILE_SPEC),
- AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME
+ AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME,
),
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt
deleted file mode 100644
index d0699aa12a43..000000000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt
+++ /dev/null
@@ -1,121 +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.qs.pipeline.domain.autoaddable
-
-import android.platform.test.annotations.DisableFlags
-import android.platform.test.annotations.EnableFlags
-import android.view.accessibility.Flags
-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.qs.ReduceBrightColorsController
-import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
-import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
-import com.android.systemui.qs.pipeline.shared.TileSpec
-import com.android.systemui.qs.tiles.ReduceBrightColorsTile
-import com.android.systemui.util.mockito.capture
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestResult
-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.ArgumentCaptor
-import org.mockito.Captor
-import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-
-@OptIn(ExperimentalCoroutinesApi::class)
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class ReduceBrightColorsAutoAddableTest : SysuiTestCase() {
-
- @Mock private lateinit var reduceBrightColorsController: ReduceBrightColorsController
- @Captor
- private lateinit var reduceBrightColorsListenerCaptor:
- ArgumentCaptor<ReduceBrightColorsController.Listener>
-
- private lateinit var underTest: ReduceBrightColorsAutoAddable
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- }
-
- @Test
- fun notAvailable_strategyDisabled() =
- testWithFeatureAvailability(available = false) {
- assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.Disabled)
- }
-
- @Test
- @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
- fun available_strategyIfNotAdded() =
- testWithFeatureAvailability(available = true) {
- assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.IfNotAdded(SPEC))
- }
-
- @Test
- @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
- fun activated_addSignal() = testWithFeatureAvailability {
- val signal by collectLastValue(underTest.autoAddSignal(0))
- runCurrent()
-
- verify(reduceBrightColorsController).addCallback(capture(reduceBrightColorsListenerCaptor))
-
- reduceBrightColorsListenerCaptor.value.onActivated(true)
-
- assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
- }
-
- @Test
- @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
- fun notActivated_noSignal() = testWithFeatureAvailability {
- val signal by collectLastValue(underTest.autoAddSignal(0))
- runCurrent()
-
- verify(reduceBrightColorsController).addCallback(capture(reduceBrightColorsListenerCaptor))
-
- reduceBrightColorsListenerCaptor.value.onActivated(false)
-
- assertThat(signal).isNull()
- }
-
- @Test
- @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
- fun available_a11yQsShortcutFlagEnabled_strategyDisabled() =
- testWithFeatureAvailability(available = true) {
- assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.Disabled)
- }
-
- private fun testWithFeatureAvailability(
- available: Boolean = true,
- body: suspend TestScope.() -> TestResult
- ) = runTest {
- underTest = ReduceBrightColorsAutoAddable(reduceBrightColorsController, available)
- body()
- }
-
- companion object {
- private val SPEC by lazy { TileSpec.create(ReduceBrightColorsTile.TILE_SPEC) }
- }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AccessibilityTilesInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AccessibilityTilesInteractorTest.kt
index 3faab5048fb4..6cd627c1d058 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AccessibilityTilesInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AccessibilityTilesInteractorTest.kt
@@ -19,9 +19,6 @@ package com.android.systemui.qs.pipeline.domain.interactor
import android.content.Context
import android.content.pm.UserInfo
import android.os.UserHandle
-import android.platform.test.annotations.DisableFlags
-import android.platform.test.annotations.EnableFlags
-import android.view.accessibility.Flags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -50,21 +47,9 @@ import org.mockito.Mockito.mock
@RunWith(AndroidJUnit4::class)
@OptIn(ExperimentalCoroutinesApi::class)
class AccessibilityTilesInteractorTest : SysuiTestCase() {
- private val USER_0_INFO =
- UserInfo(
- 0,
- "zero",
- "",
- UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL,
- )
+ private val USER_0_INFO = UserInfo(0, "zero", "", UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL)
- private val USER_1_INFO =
- UserInfo(
- 1,
- "one",
- "",
- UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL,
- )
+ private val USER_1_INFO = UserInfo(1, "one", "", UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL)
private val USER_0_TILES = listOf(TileSpec.create(ColorInversionTile.TILE_SPEC))
private val USER_1_TILES = listOf(TileSpec.create(ColorCorrectionTile.TILE_SPEC))
@@ -94,20 +79,7 @@ class AccessibilityTilesInteractorTest : SysuiTestCase() {
}
@Test
- @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
- fun currentTilesChanged_a11yQsShortcutFlagOff_nothingHappen() =
- testScope.runTest {
- underTest = createInteractor()
-
- setTiles(USER_0_TILES)
- runCurrent()
-
- assertThat(a11yQsShortcutsRepository.notifyA11yManagerTilesChangedRequests).isEmpty()
- }
-
- @Test
- @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
- fun currentTilesChanged_a11yQsShortcutFlagOn_notifyAccessibilityRepository() =
+ fun currentTilesChanged_notifyAccessibilityRepository() =
testScope.runTest {
underTest = createInteractor()
@@ -123,8 +95,7 @@ class AccessibilityTilesInteractorTest : SysuiTestCase() {
}
@Test
- @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
- fun userChanged_a11yQsShortcutFlagOn_notifyAccessibilityRepositoryWithCorrectTilesAndUser() =
+ fun userChanged_notifyAccessibilityRepositoryWithCorrectTilesAndUser() =
testScope.runTest {
underTest = createInteractor()
setTiles(USER_0_TILES)
@@ -163,7 +134,7 @@ class AccessibilityTilesInteractorTest : SysuiTestCase() {
return AccessibilityTilesInteractor(
a11yQsShortcutsRepository,
testDispatcher,
- testScope.backgroundScope
+ testScope.backgroundScope,
)
.apply { init(currentTilesInteractor) }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java
index 7d41a20e628f..307b87a74dad 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java
@@ -27,8 +27,6 @@ import static org.mockito.Mockito.when;
import android.content.Intent;
import android.os.Handler;
-import android.platform.test.annotations.DisableFlags;
-import android.platform.test.annotations.EnableFlags;
import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.testing.TestableLooper;
@@ -38,7 +36,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.accessibility.hearingaid.HearingDevicesChecker;
import com.android.systemui.accessibility.hearingaid.HearingDevicesDialogManager;
@@ -124,18 +121,6 @@ public class HearingDevicesTileTest extends SysuiTestCase {
}
@Test
- @EnableFlags(Flags.FLAG_HEARING_AIDS_QS_TILE_DIALOG)
- public void isAvailable_flagEnabled_true() {
- assertThat(mTile.isAvailable()).isTrue();
- }
-
- @Test
- @DisableFlags(Flags.FLAG_HEARING_AIDS_QS_TILE_DIALOG)
- public void isAvailable_flagDisabled_false() {
- assertThat(mTile.isAvailable()).isFalse();
- }
-
- @Test
public void longClick_expectedAction() {
mTile.longClick(null);
mTestableLooper.processAllMessages();
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
index 79556baed067..fecd8c3cacca 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
@@ -26,11 +26,9 @@ import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
-import com.android.systemui.Flags
import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingManagerFake
-import com.android.systemui.flags.setFlagValue
import com.android.systemui.keyguard.KeyguardWmStateRefactor
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -42,7 +40,6 @@ import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tiles.dialog.InternetDialogManager
import com.android.systemui.qs.tiles.dialog.WifiStateWorker
import com.android.systemui.res.R
-import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.statusbar.connectivity.AccessPointController
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
@@ -65,6 +62,7 @@ import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -150,11 +148,18 @@ class InternetTileNewImplTest(flags: FlagsParameterization) : SysuiTestCase() {
)
underTest.initialize()
+
underTest.setListening(Object(), true)
looper.processAllMessages()
}
+ @After
+ fun tearDown() {
+ underTest.destroy()
+ looper.processAllMessages()
+ }
+
@Test
fun noDefaultConnection_noNetworkAvailable() =
testScope.runTest {
@@ -272,33 +277,37 @@ class InternetTileNewImplTest(flags: FlagsParameterization) : SysuiTestCase() {
underTest.click(null)
looper.processAllMessages()
- verify(dialogManager, times(1)).create(
- aboveStatusBar = true,
- accessPointController.canConfigMobileData(),
- accessPointController.canConfigWifi(),
- null,
- )
+ verify(dialogManager, times(1))
+ .create(
+ aboveStatusBar = true,
+ accessPointController.canConfigMobileData(),
+ accessPointController.canConfigWifi(),
+ null,
+ )
}
@Test
@EnableFlags(
- value = [
- QsDetailedView.FLAG_NAME,
- FLAG_SCENE_CONTAINER,
- KeyguardWmStateRefactor.FLAG_NAME,
- NotificationThrottleHun.FLAG_NAME,
- DualShade.FLAG_NAME]
+ value =
+ [
+ QsDetailedView.FLAG_NAME,
+ FLAG_SCENE_CONTAINER,
+ KeyguardWmStateRefactor.FLAG_NAME,
+ NotificationThrottleHun.FLAG_NAME,
+ DualShade.FLAG_NAME,
+ ]
)
fun click_withQsDetailedViewEnabled() {
underTest.click(null)
looper.processAllMessages()
- verify(dialogManager, times(0)).create(
- aboveStatusBar = true,
- accessPointController.canConfigMobileData(),
- accessPointController.canConfigWifi(),
- null,
- )
+ verify(dialogManager, times(0))
+ .create(
+ aboveStatusBar = true,
+ accessPointController.canConfigMobileData(),
+ accessPointController.canConfigWifi(),
+ null,
+ )
}
companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
index c7da03dbbf30..497e33536b7f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
@@ -46,6 +46,7 @@ import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import java.util.concurrent.Executors
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -123,6 +124,12 @@ class RecordIssueTileTest : SysuiTestCase() {
)
}
+ @After
+ fun teardown() {
+ tile.destroy()
+ testableLooper.processAllMessages()
+ }
+
@Test
fun qsTileUi_shouldLookCorrect_whenInactive() {
whenever(issueRecordingState.isRecording).thenReturn(false)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/interactor/HearingDevicesTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/interactor/HearingDevicesTileDataInteractorTest.kt
index 1dfa2cd26491..9099d3d911bc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/interactor/HearingDevicesTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/interactor/HearingDevicesTileDataInteractorTest.kt
@@ -17,12 +17,9 @@
package com.android.systemui.qs.tiles.impl.hearingdevices.domain.interactor
import android.os.UserHandle
-import android.platform.test.annotations.DisableFlags
-import android.platform.test.annotations.EnableFlags
import android.platform.test.annotations.EnabledOnRavenwood
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.accessibility.hearingaid.HearingDevicesChecker
import com.android.systemui.coroutines.collectLastValue
@@ -66,24 +63,14 @@ class HearingDevicesTileDataInteractorTest : SysuiTestCase() {
underTest = HearingDevicesTileDataInteractor(testScope.testScheduler, controller, checker)
}
- @EnableFlags(Flags.FLAG_HEARING_AIDS_QS_TILE_DIALOG)
@Test
- fun availability_flagEnabled_returnTrue() =
+ fun availability_returnTrue() =
testScope.runTest {
val availability by collectLastValue(underTest.availability(testUser))
assertThat(availability).isTrue()
}
- @DisableFlags(Flags.FLAG_HEARING_AIDS_QS_TILE_DIALOG)
- @Test
- fun availability_flagDisabled_returnFalse() =
- testScope.runTest {
- val availability by collectLastValue(underTest.availability(testUser))
-
- assertThat(availability).isFalse()
- }
-
@Test
fun tileData_bluetoothStateChanged_dataMatchesChecker() =
testScope.runTest {
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
index 44e6b4d2d0f6..029a2f91a4ba 100644
--- 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
@@ -58,7 +58,9 @@ class ModesTileDataInteractorTest : SysuiTestCase() {
private val dispatcher = kosmos.testDispatcher
private val zenModeRepository = kosmos.fakeZenModeRepository
- private val underTest = ModesTileDataInteractor(context, kosmos.zenModeInteractor, dispatcher)
+ private val underTest by lazy {
+ ModesTileDataInteractor(context, kosmos.zenModeInteractor, dispatcher)
+ }
@Before
fun setUp() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelTest.kt
index 7ab8ab93c024..dce110201e1d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelTest.kt
@@ -39,6 +39,9 @@ import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shade.shared.flag.DualShade
+import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationStackAppearanceInteractor
+import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds
+import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -143,6 +146,23 @@ class QuickSettingsShadeOverlayContentViewModelTest : SysuiTestCase() {
assertThat(underTest.showHeader).isFalse()
}
+ @Test
+ fun onPanelShapeChanged() =
+ testScope.runTest {
+ val actual by
+ collectLastValue(kosmos.notificationStackAppearanceInteractor.qsPanelShape)
+ val expected =
+ ShadeScrimShape(
+ bounds = ShadeScrimBounds(left = 10f, top = 0f, right = 710f, bottom = 600f),
+ topRadius = 0,
+ bottomRadius = 100,
+ )
+
+ underTest.onPanelShapeChanged(expected)
+
+ assertThat(expected).isEqualTo(actual)
+ }
+
private fun TestScope.lockDevice() {
val currentScene by collectLastValue(sceneInteractor.currentScene)
kosmos.powerInteractor.setAsleepForTest()
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 51f056aa18da..cb7267b2c34c 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
@@ -1508,10 +1508,8 @@ class SceneContainerStartableTest : SysuiTestCase() {
}
@Test
- fun collectFalsingSignals_screenOnAndOff_aodUnavailable() =
+ fun collectFalsingSignals_screenOnAndOff() =
testScope.runTest {
- kosmos.fakeKeyguardRepository.setAodAvailable(false)
- runCurrent()
prepareState(
initialSceneKey = Scenes.Lockscreen,
authenticationMethod = AuthenticationMethodModel.Pin,
@@ -1556,53 +1554,6 @@ class SceneContainerStartableTest : SysuiTestCase() {
}
@Test
- fun collectFalsingSignals_screenOnAndOff_aodAvailable() =
- testScope.runTest {
- kosmos.fakeKeyguardRepository.setAodAvailable(true)
- runCurrent()
- prepareState(
- initialSceneKey = Scenes.Lockscreen,
- authenticationMethod = AuthenticationMethodModel.Pin,
- isDeviceUnlocked = false,
- )
- underTest.start()
- runCurrent()
- verify(falsingCollector, never()).onScreenTurningOn()
- verify(falsingCollector, never()).onScreenOnFromTouch()
- verify(falsingCollector, never()).onScreenOff()
-
- powerInteractor.setAwakeForTest(reason = PowerManager.WAKE_REASON_POWER_BUTTON)
- runCurrent()
- verify(falsingCollector, never()).onScreenTurningOn()
- verify(falsingCollector, never()).onScreenOnFromTouch()
- verify(falsingCollector, never()).onScreenOff()
-
- powerInteractor.setAsleepForTest()
- runCurrent()
- verify(falsingCollector, never()).onScreenTurningOn()
- verify(falsingCollector, never()).onScreenOnFromTouch()
- verify(falsingCollector, never()).onScreenOff()
-
- powerInteractor.setAwakeForTest(reason = PowerManager.WAKE_REASON_TAP)
- runCurrent()
- verify(falsingCollector, never()).onScreenTurningOn()
- verify(falsingCollector, never()).onScreenOnFromTouch()
- verify(falsingCollector, never()).onScreenOff()
-
- powerInteractor.setAsleepForTest()
- runCurrent()
- verify(falsingCollector, never()).onScreenTurningOn()
- verify(falsingCollector, never()).onScreenOnFromTouch()
- verify(falsingCollector, never()).onScreenOff()
-
- powerInteractor.setAwakeForTest(reason = PowerManager.WAKE_REASON_POWER_BUTTON)
- runCurrent()
- verify(falsingCollector, never()).onScreenTurningOn()
- verify(falsingCollector, never()).onScreenOnFromTouch()
- verify(falsingCollector, never()).onScreenOff()
- }
-
- @Test
fun collectFalsingSignals_bouncerVisibility() =
testScope.runTest {
prepareState(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt
index fd9f5f02ee62..20dfd3e11947 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt
@@ -18,6 +18,7 @@ package com.android.systemui.shade.display
import android.view.Display
import android.view.Display.TYPE_EXTERNAL
+import android.view.MotionEvent
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -28,11 +29,16 @@ import com.android.systemui.display.data.repository.displayRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.shade.domain.interactor.notificationElement
+import com.android.systemui.shade.domain.interactor.qsElement
+import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
import kotlinx.coroutines.test.runTest
import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -50,9 +56,19 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() {
keyguardRepository,
testScope.backgroundScope,
shadeOnDefaultDisplayWhenLocked = shadeOnDefaultDisplayWhenLocked,
+ shadeInteractor = { kosmos.shadeInteractor },
+ { kosmos.qsElement },
+ { kosmos.notificationElement },
)
}
+ private fun createMotionEventForDisplay(displayId: Int, xCoordinate: Float = 0f): MotionEvent {
+ return mock<MotionEvent> {
+ on { getX() } doReturn xCoordinate
+ on { getDisplayId() } doReturn displayId
+ }
+ }
+
@Test
fun displayId_defaultToDefaultDisplay() {
val underTest = createUnderTest()
@@ -67,7 +83,7 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() {
val displayId by collectLastValue(underTest.displayId)
displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL))
- underTest.onStatusBarTouched(2)
+ underTest.onStatusBarTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH)
assertThat(displayId).isEqualTo(2)
}
@@ -79,7 +95,7 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() {
val displayIds by collectValues(underTest.displayId)
assertThat(displayIds).isEqualTo(listOf(Display.DEFAULT_DISPLAY))
- underTest.onStatusBarTouched(2)
+ underTest.onStatusBarTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH)
// Never set, as 2 was not a display according to the repository.
assertThat(displayIds).isEqualTo(listOf(Display.DEFAULT_DISPLAY))
@@ -92,7 +108,7 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() {
val displayId by collectLastValue(underTest.displayId)
displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL))
- underTest.onStatusBarTouched(2)
+ underTest.onStatusBarTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH)
assertThat(displayId).isEqualTo(2)
@@ -108,7 +124,7 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() {
val displayId by collectLastValue(underTest.displayId)
displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL))
- underTest.onStatusBarTouched(2)
+ underTest.onStatusBarTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH)
assertThat(displayId).isEqualTo(2)
@@ -124,7 +140,7 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() {
val displayId by collectLastValue(underTest.displayId)
displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL))
- underTest.onStatusBarTouched(2)
+ underTest.onStatusBarTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH)
assertThat(displayId).isEqualTo(2)
@@ -136,4 +152,48 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() {
assertThat(displayId).isEqualTo(2)
}
+
+ @Test
+ fun onStatusBarTouched_leftSide_intentSetToNotifications() =
+ testScope.runTest {
+ val underTest = createUnderTest(shadeOnDefaultDisplayWhenLocked = true)
+
+ underTest.onStatusBarTouched(
+ createMotionEventForDisplay(2, STATUS_BAR_WIDTH * 0.1f),
+ STATUS_BAR_WIDTH,
+ )
+
+ assertThat(underTest.consumeExpansionIntent()).isEqualTo(kosmos.notificationElement)
+ }
+
+ @Test
+ fun onStatusBarTouched_rightSide_intentSetToQs() =
+ testScope.runTest {
+ val underTest = createUnderTest(shadeOnDefaultDisplayWhenLocked = true)
+
+ underTest.onStatusBarTouched(
+ createMotionEventForDisplay(2, STATUS_BAR_WIDTH * 0.95f),
+ STATUS_BAR_WIDTH,
+ )
+
+ assertThat(underTest.consumeExpansionIntent()).isEqualTo(kosmos.qsElement)
+ }
+
+ @Test
+ fun onStatusBarTouched_nullAfterConsumed() =
+ testScope.runTest {
+ val underTest = createUnderTest(shadeOnDefaultDisplayWhenLocked = true)
+
+ underTest.onStatusBarTouched(
+ createMotionEventForDisplay(2, STATUS_BAR_WIDTH * 0.1f),
+ STATUS_BAR_WIDTH,
+ )
+ assertThat(underTest.consumeExpansionIntent()).isEqualTo(kosmos.notificationElement)
+
+ assertThat(underTest.consumeExpansionIntent()).isNull()
+ }
+
+ companion object {
+ private const val STATUS_BAR_WIDTH = 100
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractorTest.kt
index 58396e7cef82..8aa8a50afcd4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractorTest.kt
@@ -22,8 +22,6 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
-import com.android.systemui.shade.domain.interactor.ShadeExpandedStateInteractorImpl.NotificationElement
-import com.android.systemui.shade.domain.interactor.ShadeExpandedStateInteractorImpl.QSElement
import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
@@ -52,7 +50,7 @@ class ShadeExpandedStateInteractorTest : SysuiTestCase() {
val element = currentlyExpandedElement.value
- assertThat(element).isInstanceOf(QSElement::class.java)
+ assertThat(element).isInstanceOf(QSShadeElement::class.java)
}
@Test
@@ -62,7 +60,7 @@ class ShadeExpandedStateInteractorTest : SysuiTestCase() {
val element = underTest.currentlyExpandedElement.value
- assertThat(element).isInstanceOf(NotificationElement::class.java)
+ assertThat(element).isInstanceOf(NotificationShadeElement::class.java)
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/customization/data/SensorLocationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/customization/data/SensorLocationTest.kt
new file mode 100644
index 000000000000..526fd45533c7
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/customization/data/SensorLocationTest.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.customization.data
+
+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.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SensorLocationTest : SysuiTestCase() {
+
+ @Test
+ fun encodeAndDecode() {
+ val sensorLocation = SensorLocation(640, 2068, 117, 0.75f)
+
+ assertThat(SensorLocation.decode(sensorLocation.encode())).isEqualTo(sensorLocation)
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
index ac3089d9286b..56a4ed078670 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
@@ -30,10 +30,12 @@ import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.activityStarter
import com.android.systemui.res.R
import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
import com.android.systemui.statusbar.chips.ui.model.ColorsModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository
import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
import com.android.systemui.statusbar.phone.ongoingcall.shared.model.inCallModel
@@ -64,7 +66,7 @@ class CallChipViewModelTest : SysuiTestCase() {
.thenReturn(chipBackgroundView)
}
- private val underTest = kosmos.callChipViewModel
+ private val underTest by lazy { kosmos.callChipViewModel }
@Test
fun chip_noCall_isHidden() =
@@ -219,28 +221,94 @@ class CallChipViewModelTest : SysuiTestCase() {
}
@Test
- fun chip_positiveStartTime_colorsAreThemed() =
+ fun chip_positiveStartTime_notPromoted_colorsAreThemed() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
- repo.setOngoingCallState(inCallModel(startTimeMs = 1000))
+ repo.setOngoingCallState(inCallModel(startTimeMs = 1000, promotedContent = null))
assertThat((latest as OngoingActivityChipModel.Shown).colors)
.isEqualTo(ColorsModel.Themed)
}
@Test
- fun chip_zeroStartTime_colorsAreThemed() =
+ fun chip_zeroStartTime_notPromoted_colorsAreThemed() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
- repo.setOngoingCallState(inCallModel(startTimeMs = 0))
+ repo.setOngoingCallState(inCallModel(startTimeMs = 0, promotedContent = null))
+
+ assertThat((latest as OngoingActivityChipModel.Shown).colors)
+ .isEqualTo(ColorsModel.Themed)
+ }
+
+ @Test
+ @DisableFlags(StatusBarNotifChips.FLAG_NAME)
+ fun chip_positiveStartTime_promoted_notifChipsFlagOff_colorsAreThemed() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ repo.setOngoingCallState(
+ inCallModel(startTimeMs = 1000, promotedContent = PROMOTED_CONTENT_WITH_COLOR)
+ )
assertThat((latest as OngoingActivityChipModel.Shown).colors)
.isEqualTo(ColorsModel.Themed)
}
@Test
+ @DisableFlags(StatusBarNotifChips.FLAG_NAME)
+ fun chip_zeroStartTime_promoted_notifChipsFlagOff_colorsAreThemed() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ repo.setOngoingCallState(
+ inCallModel(startTimeMs = 0, promotedContent = PROMOTED_CONTENT_WITH_COLOR)
+ )
+
+ assertThat((latest as OngoingActivityChipModel.Shown).colors)
+ .isEqualTo(ColorsModel.Themed)
+ }
+
+ @Test
+ @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+ fun chip_positiveStartTime_promoted_notifChipsFlagOn_colorsAreCustom() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ repo.setOngoingCallState(
+ inCallModel(startTimeMs = 1000, promotedContent = PROMOTED_CONTENT_WITH_COLOR)
+ )
+
+ assertThat((latest as OngoingActivityChipModel.Shown).colors)
+ .isEqualTo(
+ ColorsModel.Custom(
+ backgroundColorInt = PROMOTED_BACKGROUND_COLOR,
+ primaryTextColorInt = PROMOTED_PRIMARY_TEXT_COLOR,
+ )
+ )
+ }
+
+ @Test
+ @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+ fun chip_zeroStartTime_promoted_notifChipsFlagOff_colorsAreCustom() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ repo.setOngoingCallState(
+ inCallModel(startTimeMs = 0, promotedContent = PROMOTED_CONTENT_WITH_COLOR)
+ )
+
+ assertThat((latest as OngoingActivityChipModel.Shown).colors)
+ .isEqualTo(
+ ColorsModel.Custom(
+ backgroundColorInt = PROMOTED_BACKGROUND_COLOR,
+ primaryTextColorInt = PROMOTED_PRIMARY_TEXT_COLOR,
+ )
+ )
+ }
+
+ @Test
fun chip_resetsCorrectly() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -319,5 +387,19 @@ class CallChipViewModelTest : SysuiTestCase() {
} else {
mock<StatusBarIconView>()
}
+
+ private val PROMOTED_CONTENT_WITH_COLOR =
+ PromotedNotificationContentModel.Builder("notif")
+ .apply {
+ this.colors =
+ PromotedNotificationContentModel.Colors(
+ backgroundColor = PROMOTED_BACKGROUND_COLOR,
+ primaryTextColor = PROMOTED_PRIMARY_TEXT_COLOR,
+ )
+ }
+ .build()
+
+ private const val PROMOTED_BACKGROUND_COLOR = 65
+ private const val PROMOTED_PRIMARY_TEXT_COLOR = 98
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
index ee4a52d35d68..e89c929a5827 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
@@ -36,6 +36,7 @@ import com.android.systemui.statusbar.notification.data.repository.ActiveNotific
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
+import com.android.systemui.statusbar.notification.shared.CallType
import com.android.systemui.testKosmos
import com.android.systemui.util.time.fakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -178,6 +179,37 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() {
assertThat(latest!![1].statusBarChipIconView).isEqualTo(secondIcon)
}
+ /** Regression test for b/388521980. */
+ @Test
+ @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+ fun notificationChips_callNotifIsAlsoPromoted_callNotifExcluded() =
+ kosmos.runTest {
+ val latest by collectLastValue(underTest.notificationChips)
+
+ setNotifs(
+ listOf(
+ activeNotificationModel(
+ key = "promotedNormal",
+ statusBarChipIcon = mock(),
+ promotedContent =
+ PromotedNotificationContentModel.Builder("promotedNormal").build(),
+ callType = CallType.None,
+ ),
+ activeNotificationModel(
+ key = "promotedCall",
+ statusBarChipIcon = mock(),
+ promotedContent =
+ PromotedNotificationContentModel.Builder("promotedCall").build(),
+ callType = CallType.Ongoing,
+ ),
+ )
+ )
+
+ // Verify the promoted call notification is not included
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0].key).isEqualTo("promotedNormal")
+ }
+
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
fun notificationChips_notifUpdatesGoThrough() =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt
index 1df2553d0eb8..c3547bc5cc9b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt
@@ -74,7 +74,8 @@ class NotificationStackAppearanceIntegrationTest : SysuiTestCase() {
testScope.runTest {
val radius = MutableStateFlow(32)
val leftOffset = MutableStateFlow(0)
- val shape by collectLastValue(scrollViewModel.shadeScrimShape(radius, leftOffset))
+ val shape by
+ collectLastValue(scrollViewModel.notificationScrimShape(radius, leftOffset))
// When: receive scrim bounds
placeholderViewModel.onScrimBoundsChanged(
@@ -87,7 +88,7 @@ class NotificationStackAppearanceIntegrationTest : SysuiTestCase() {
bounds =
ShadeScrimBounds(left = 0f, top = 200f, right = 100f, bottom = 550f),
topRadius = 32,
- bottomRadius = 0
+ bottomRadius = 0,
)
)
@@ -104,7 +105,7 @@ class NotificationStackAppearanceIntegrationTest : SysuiTestCase() {
bounds =
ShadeScrimBounds(left = 10f, top = 200f, right = 100f, bottom = 550f),
topRadius = 24,
- bottomRadius = 0
+ bottomRadius = 0,
)
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
index 657fffb1875d..7b120947b1d6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
@@ -16,17 +16,21 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
-import static com.android.systemui.flags.SceneContainerFlagParameterizationKt.parameterizeSceneContainerFlag;
+import static android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf;
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertFalse;
+
+import static org.junit.Assume.assumeFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -48,6 +52,7 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.BrokenWithSceneContainer;
import com.android.systemui.flags.DisableSceneContainer;
import com.android.systemui.flags.EnableSceneContainer;
+import com.android.systemui.flags.SceneContainerFlagParameterizationKt;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.keyguard.shared.model.TransitionState;
@@ -86,9 +91,11 @@ import org.mockito.MockitoAnnotations;
import org.mockito.verification.VerificationMode;
import java.util.List;
+import java.util.Set;
import kotlinx.coroutines.flow.MutableStateFlow;
import kotlinx.coroutines.test.TestScope;
+
import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
import platform.test.runner.parameterized.Parameters;
@@ -99,7 +106,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
@Parameters(name = "{0}")
public static List<FlagsParameterization> getParams() {
- return parameterizeSceneContainerFlag();
+ return SceneContainerFlagParameterizationKt
+ .andSceneContainer(allCombinationsOf(Flags.FLAG_STABILIZE_HEADS_UP_GROUP));
}
private VisualStabilityCoordinator mCoordinator;
@@ -122,7 +130,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
private FakeSystemClock mFakeSystemClock = new FakeSystemClock();
- private FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock);
+ private FakeExecutor mFakeBackgroundExecutor = new FakeExecutor(mFakeSystemClock);
+ private FakeExecutor mFakeMainExecutor = new FakeExecutor(mFakeSystemClock);
private final TestScope mTestScope = mKosmos.getTestScope();
private final JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope.getBackgroundScope());
@@ -147,7 +156,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
mShadeAnimationInteractor = new ShadeAnimationInteractorLegacyImpl(
new ShadeAnimationRepository(), mShadeRepository);
mCoordinator = new VisualStabilityCoordinator(
- mFakeExecutor,
+ mFakeBackgroundExecutor,
+ mFakeMainExecutor,
mDumpManager,
mHeadsUpManager,
mShadeAnimationInteractor,
@@ -417,8 +427,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
assertTrue(mNotifStabilityManager.isSectionChangeAllowed(mEntry));
// WHEN the timeout for the temporarily allow section reordering runnable is finsihed
- mFakeExecutor.advanceClockToNext();
- mFakeExecutor.runNextReady();
+ mFakeBackgroundExecutor.advanceClockToNext();
+ mFakeBackgroundExecutor.runNextReady();
// THEN section changes aren't allowed anymore
assertFalse(mNotifStabilityManager.isSectionChangeAllowed(mEntry));
@@ -701,6 +711,212 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
assertFalse(mNotifStabilityManager.isGroupPruneAllowed(mGroupEntry));
}
+ @Test
+ public void everyChangeAllowed_onReorderingEnabled_legacy() {
+ assumeFalse(StabilizeHeadsUpGroup.isEnabled());
+ // GIVEN - reordering is allowed.
+ setPulsing(false);
+ setPanelExpanded(false);
+
+ // THEN
+ assertThat(mNotifStabilityManager.isEveryChangeAllowed()).isTrue();
+ assertThat(mNotifStabilityManager.isGroupChangeAllowed(any())).isTrue();
+ assertThat(mNotifStabilityManager.isGroupPruneAllowed(any())).isTrue();
+ assertThat(mNotifStabilityManager.isSectionChangeAllowed(any())).isTrue();
+ assertThat(mNotifStabilityManager.isEntryReorderingAllowed(any())).isTrue();
+ }
+
+ @Test
+ public void everyChangeAllowed_noActiveHeadsUpGroup_onReorderingEnabled() {
+ assumeTrue(StabilizeHeadsUpGroup.isEnabled());
+ // GIVEN - reordering is allowed.
+ setPulsing(false);
+ setPanelExpanded(false);
+
+ // GIVEN - empty heads-up-group keys
+ mCoordinator.setHeadsUpGroupKeys(Set.of());
+
+ // THEN
+ assertThat(mNotifStabilityManager.isEveryChangeAllowed()).isTrue();
+ assertThat(mNotifStabilityManager.isGroupChangeAllowed(any())).isTrue();
+ assertThat(mNotifStabilityManager.isGroupPruneAllowed(any())).isTrue();
+ assertThat(mNotifStabilityManager.isSectionChangeAllowed(any())).isTrue();
+ assertThat(mNotifStabilityManager.isEntryReorderingAllowed(any())).isTrue();
+ }
+
+ @Test
+ public void everyChangeDisallowed_activeHeadsUpGroup_onReorderingEnabled() {
+ assumeTrue(StabilizeHeadsUpGroup.isEnabled());
+ // GIVEN - reordering is allowed.
+ setPulsing(false);
+ setPanelExpanded(false);
+
+ // GIVEN - there is a group heads-up.
+ mCoordinator.setHeadsUpGroupKeys(Set.of("heads_up_group_key"));
+
+ // THEN
+ assertThat(mNotifStabilityManager.isEveryChangeAllowed()).isFalse();
+ }
+
+ @Test
+ public void nonHeadsUpGroup_changesAllowed_onReorderingEnabled() {
+ assumeTrue(StabilizeHeadsUpGroup.isEnabled());
+ // GIVEN - reordering is allowed.
+ setPulsing(false);
+ setPanelExpanded(false);
+
+ // GIVEN - there is a group heads-up.
+ String headsUpGroupKey = "heads_up_group_key";
+ mCoordinator.setHeadsUpGroupKeys(Set.of(headsUpGroupKey));
+ when(mHeadsUpManager.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true);
+
+ // GIVEN - HUN Group Summary
+ final NotificationEntry nonHeadsUpGroupSummary = mock(NotificationEntry.class);
+ when(nonHeadsUpGroupSummary.getKey()).thenReturn("non_heads_up_group_key");
+ when(nonHeadsUpGroupSummary.isSummaryWithChildren()).thenReturn(true);
+ final GroupEntry nonHeadsUpGroupEntry = mock(GroupEntry.class);
+ when(nonHeadsUpGroupEntry.getSummary()).thenReturn(nonHeadsUpGroupSummary);
+ when(nonHeadsUpGroupEntry.getRepresentativeEntry()).thenReturn(nonHeadsUpGroupSummary);
+
+ // THEN
+ assertThat(mNotifStabilityManager.isGroupPruneAllowed(nonHeadsUpGroupEntry)).isTrue();
+ assertThat(mNotifStabilityManager.isEntryReorderingAllowed(nonHeadsUpGroupEntry)).isTrue();
+ }
+
+ @Test
+ public void headsUpGroup_changesDisallowed_onReorderingEnabled() {
+ assumeTrue(StabilizeHeadsUpGroup.isEnabled());
+ // GIVEN - reordering is allowed.
+ setPulsing(false);
+ setPanelExpanded(false);
+
+ // GIVEN - there is a group heads-up.
+ final String headsUpGroupKey = "heads_up_group_key";
+ mCoordinator.setHeadsUpGroupKeys(Set.of(headsUpGroupKey));
+ when(mHeadsUpManager.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true);
+
+ // GIVEN - HUN Group
+ final NotificationEntry headsUpGroupSummary = mock(NotificationEntry.class);
+ when(headsUpGroupSummary.rowIsChildInGroup()).thenReturn(false);
+ when(headsUpGroupSummary.getKey()).thenReturn(headsUpGroupKey);
+ when(headsUpGroupSummary.isSummaryWithChildren()).thenReturn(true);
+
+ final GroupEntry headsUpGroupEntry = mock(GroupEntry.class);
+ when(headsUpGroupEntry.getSummary()).thenReturn(headsUpGroupSummary);
+ when(headsUpGroupEntry.getRepresentativeEntry()).thenReturn(headsUpGroupSummary);
+
+ when(headsUpGroupSummary.getParent()).thenReturn(headsUpGroupEntry);
+
+ // GIVEN - HUN is in visible location
+ when(mVisibilityLocationProvider.isInVisibleLocation(headsUpGroupSummary)).thenReturn(true);
+
+ // THEN
+ assertThat(mNotifStabilityManager.isGroupPruneAllowed(headsUpGroupEntry)).isFalse();
+ assertThat(mNotifStabilityManager.isEntryReorderingAllowed(headsUpGroupEntry)).isFalse();
+ }
+
+ @Test
+ public void headsUpGroupSummaries_changesDisallowed_onReorderingEnabled() {
+ assumeTrue(StabilizeHeadsUpGroup.isEnabled());
+ // GIVEN - reordering is allowed.
+ setPulsing(false);
+ setPanelExpanded(false);
+
+ // GIVEN - there is a group heads-up.
+ final String headsUpGroupKey = "heads_up_group_key";
+ mCoordinator.setHeadsUpGroupKeys(Set.of(headsUpGroupKey));
+ when(mHeadsUpManager.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true);
+
+ // GIVEN - HUN Group
+ final NotificationEntry headsUpGroupSummary = mock(NotificationEntry.class);
+ when(headsUpGroupSummary.rowIsChildInGroup()).thenReturn(false);
+ when(headsUpGroupSummary.getKey()).thenReturn(headsUpGroupKey);
+ when(headsUpGroupSummary.isSummaryWithChildren()).thenReturn(true);
+
+ final GroupEntry headsUpGroupEntry = mock(GroupEntry.class);
+ when(headsUpGroupEntry.getSummary()).thenReturn(headsUpGroupSummary);
+ when(headsUpGroupEntry.getRepresentativeEntry()).thenReturn(headsUpGroupSummary);
+
+ when(headsUpGroupSummary.getParent()).thenReturn(headsUpGroupEntry);
+
+ // GIVEN - HUN is in visible location
+ when(mVisibilityLocationProvider.isInVisibleLocation(headsUpGroupSummary)).thenReturn(true);
+
+ // THEN
+ assertThat(mNotifStabilityManager.isGroupChangeAllowed(headsUpGroupSummary)).isFalse();
+ assertThat(mNotifStabilityManager.isEntryReorderingAllowed(headsUpGroupSummary)).isFalse();
+ assertThat(mNotifStabilityManager.isSectionChangeAllowed(headsUpGroupSummary)).isFalse();
+ }
+
+ @Test
+ public void notificationInNonHUNGroup_changesAllowed_onReorderingEnabled() {
+ assumeTrue(StabilizeHeadsUpGroup.isEnabled());
+ // GIVEN - reordering is allowed.
+ setPulsing(false);
+ setPanelExpanded(false);
+
+ // GIVEN - there is a group heads-up.
+ String headsUpGroupKey = "heads_up_group_key";
+ mCoordinator.setHeadsUpGroupKeys(Set.of(headsUpGroupKey));
+ when(mHeadsUpManager.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true);
+
+ // GIVEN - non HUN parent Group Summary
+ final NotificationEntry groupSummary = mock(NotificationEntry.class);
+ when(groupSummary.getKey()).thenReturn("non_heads_up_group_key");
+ when(groupSummary.isSummaryWithChildren()).thenReturn(true);
+
+ final GroupEntry nonHeadsUpGroupEntry = mock(GroupEntry.class);
+ when(nonHeadsUpGroupEntry.getSummary()).thenReturn(groupSummary);
+ when(nonHeadsUpGroupEntry.getRepresentativeEntry()).thenReturn(groupSummary);
+
+ // GIVEN - child entry in a non heads-up group.
+ final NotificationEntry childEntry = mock(NotificationEntry.class);
+ when(childEntry.rowIsChildInGroup()).thenReturn(true);
+ when(childEntry.getParent()).thenReturn(nonHeadsUpGroupEntry);
+ when(childEntry.getParent()).thenReturn(nonHeadsUpGroupEntry);
+
+ // THEN
+ assertThat(mNotifStabilityManager.isGroupChangeAllowed(childEntry)).isTrue();
+ assertThat(mNotifStabilityManager.isSectionChangeAllowed(childEntry)).isTrue();
+ assertThat(mNotifStabilityManager.isEntryReorderingAllowed(nonHeadsUpGroupEntry)).isTrue();
+ }
+
+ @Test
+ public void notificationInHUNGroup_changesDisallowed_reorderingEnabled() {
+ assumeTrue(StabilizeHeadsUpGroup.isEnabled());
+ // GIVEN - reordering is allowed.
+ setPulsing(false);
+ setPanelExpanded(false);
+
+ // GIVEN - there is a group heads-up.
+ final String headsUpGroupKey = "heads_up_group_key";
+ mCoordinator.setHeadsUpGroupKeys(Set.of(headsUpGroupKey));
+ when(mHeadsUpManager.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true);
+
+ // GIVEN - HUN Group Summary
+ final NotificationEntry headsUpGroupSummary = mock(NotificationEntry.class);
+ when(headsUpGroupSummary.rowIsChildInGroup()).thenReturn(false);
+ when(headsUpGroupSummary.getKey()).thenReturn(headsUpGroupKey);
+ when(headsUpGroupSummary.isSummaryWithChildren()).thenReturn(true);
+
+ final GroupEntry nonHeadsUpGroupEntry = mock(GroupEntry.class);
+ when(nonHeadsUpGroupEntry.getSummary()).thenReturn(headsUpGroupSummary);
+ when(nonHeadsUpGroupEntry.getRepresentativeEntry()).thenReturn(headsUpGroupSummary);
+
+ // GIVEN - child entry in a non heads-up group.
+ final NotificationEntry childEntry = mock(NotificationEntry.class);
+ when(childEntry.rowIsChildInGroup()).thenReturn(true);
+ when(childEntry.getParent()).thenReturn(nonHeadsUpGroupEntry);
+
+ // GIVEN - HUN is in visible location
+ when(mVisibilityLocationProvider.isInVisibleLocation(headsUpGroupSummary)).thenReturn(true);
+
+ // THEN
+ assertThat(mNotifStabilityManager.isGroupChangeAllowed(childEntry)).isFalse();
+ assertThat(mNotifStabilityManager.isSectionChangeAllowed(childEntry)).isFalse();
+ assertThat(mNotifStabilityManager.isEntryReorderingAllowed(childEntry)).isFalse();
+ }
+
private void verifyStabilityManagerWasInvalidated(VerificationMode mode) {
verify(mInvalidateListener, mode).onPluggableInvalidated(eq(mNotifStabilityManager), any());
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModelTest.kt
index 3d5d1eddf581..9a42f5b02395 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModelTest.kt
@@ -54,7 +54,7 @@ class EmptyShadeViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
private val activeNotificationListRepository = kosmos.activeNotificationListRepository
private val fakeSecureSettingsRepository = kosmos.fakeSecureSettingsRepository
- private val underTest = kosmos.emptyShadeViewModel
+ private val underTest by lazy { kosmos.emptyShadeViewModel }
companion object {
@JvmStatic
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt
index 739a9c956178..9dfc922eb7d0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.headsup
import android.app.Notification
+import android.app.Notification.FLAG_PROMOTED_ONGOING
import android.app.PendingIntent
import android.app.Person
import android.os.Handler
@@ -677,10 +678,12 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() {
}
@Test
- fun testIsSticky_rowPinnedAndExpanded_true() {
- val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
- val row = testHelper.createRow()
- row.setPinnedStatus(PinnedStatus.PinnedBySystem)
+ @DisableFlags(StatusBarNotifChips.FLAG_NAME)
+ fun testIsSticky_promotedAndExpanded_notifChipsFlagOff_true() {
+ val notif = Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+ notif.flags = FLAG_PROMOTED_ONGOING
+ val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, notif)
+ val row = testHelper.createRow().apply { setPinnedStatus(PinnedStatus.PinnedBySystem) }
notifEntry.row = row
underTest.showNotification(notifEntry)
@@ -692,6 +695,23 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() {
}
@Test
+ @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+ fun testIsSticky_promotedAndExpanded_notifChipsFlagOn_false() {
+ val notif = Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+ notif.flags = FLAG_PROMOTED_ONGOING
+ val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, notif)
+ val row = testHelper.createRow().apply { setPinnedStatus(PinnedStatus.PinnedBySystem) }
+ notifEntry.row = row
+
+ underTest.showNotification(notifEntry)
+
+ val headsUpEntry = underTest.getHeadsUpEntry(notifEntry.key)
+ headsUpEntry!!.setExpanded(true)
+
+ assertThat(underTest.isSticky(notifEntry.key)).isFalse()
+ }
+
+ @Test
fun testIsSticky_remoteInputActive_true() {
val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
index d86c6efce284..ba73504b2a03 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.notification.icon.ui.viewmodel
import android.graphics.Rect
import android.graphics.drawable.Icon
+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
@@ -36,6 +38,7 @@ 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.shadeTestUtil
+import com.android.systemui.statusbar.headsup.shared.StatusBarNoHunBehavior
import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
@@ -258,6 +261,7 @@ class NotificationIconContainerStatusBarViewModelTest(flags: FlagsParameterizati
}
@Test
+ @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
fun isolatedIcon_animateOnAppear_shadeCollapsed() =
testScope.runTest {
val icon: Icon = mock()
@@ -285,6 +289,7 @@ class NotificationIconContainerStatusBarViewModelTest(flags: FlagsParameterizati
}
@Test
+ @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
fun isolatedIcon_dontAnimateOnAppear_shadeExpanded() =
testScope.runTest {
val icon: Icon = mock()
@@ -312,6 +317,7 @@ class NotificationIconContainerStatusBarViewModelTest(flags: FlagsParameterizati
}
@Test
+ @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
fun isolatedIcon_updateWhenIconDataChanges() =
testScope.runTest {
val icon: Icon = mock()
@@ -339,6 +345,7 @@ class NotificationIconContainerStatusBarViewModelTest(flags: FlagsParameterizati
}
@Test
+ @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
fun isolatedIcon_lastMessageIsFromReply_notNull() =
testScope.runTest {
val icon: Icon = mock()
@@ -362,4 +369,32 @@ class NotificationIconContainerStatusBarViewModelTest(flags: FlagsParameterizati
assertThat(isolatedIcon?.value?.notifKey).isEqualTo("notif1")
}
+
+ @Test
+ @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+ fun isolatedIcon_noHunBehaviorFlagEnabled_doesNothing() =
+ testScope.runTest {
+ val icon: Icon = mock()
+ val isolatedIcon by collectLastValue(underTest.isolatedIcon)
+ runCurrent()
+
+ headsUpViewStateRepository.isolatedNotification.value = "notif1"
+ runCurrent()
+
+ activeNotificationsRepository.activeNotifications.value =
+ ActiveNotificationsStore.Builder()
+ .apply {
+ addIndividualNotif(
+ activeNotificationModel(
+ key = "notif1",
+ groupKey = "group",
+ statusBarIcon = icon,
+ )
+ )
+ }
+ .build()
+ runCurrent()
+
+ assertThat(isolatedIcon?.value).isNull()
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
index f7673da6dfb0..4c87e47b8911 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
@@ -26,12 +26,10 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
-
import androidx.core.os.CancellationSignal;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import com.android.internal.util.NotificationMessagingUtil;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -51,7 +49,6 @@ import java.util.concurrent.atomic.AtomicReference;
@SmallTest
public class HeadsUpViewBinderTest extends SysuiTestCase {
private HeadsUpViewBinder mViewBinder;
- @Mock private NotificationMessagingUtil mNotificationMessagingUtil;
@Mock private RowContentBindStage mBindStage;
private final HeadsUpViewBinderLogger mLogger = spy(
new HeadsUpViewBinderLogger(logcatLogBuffer()));
@@ -61,7 +58,7 @@ public class HeadsUpViewBinderTest extends SysuiTestCase {
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mViewBinder = new HeadsUpViewBinder(mNotificationMessagingUtil, mBindStage, mLogger);
+ mViewBinder = new HeadsUpViewBinder(mBindStage, mLogger);
when(mEntry.getKey()).thenReturn("key");
when(mEntry.getRow()).thenReturn(mRow);
when(mBindStage.getStageParams(eq(mEntry))).thenReturn(new RowContentBindParams());
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index a49a66fe26b2..da31cd967a36 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -163,42 +163,6 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
}
@Test
- public void testIncreasedHeadsUpBeingUsed() {
- BindParams params = new BindParams(false, false, /* usesIncreasedHeadsUpHeight */ true,
- REDACTION_TYPE_NONE);
- Notification.Builder builder = spy(mBuilder);
- mNotificationInflater.inflateNotificationViews(
- mRow.getEntry(),
- mRow,
- params,
- true /* inflateSynchronously */,
- FLAG_CONTENT_VIEW_ALL,
- builder,
- mContext,
- mContext,
- mSmartReplyStateInflater);
- verify(builder).createHeadsUpContentView(true);
- }
-
- @Test
- public void testIncreasedHeightBeingUsed() {
- BindParams params = new BindParams(false, /* usesIncreasedHeight */ true, false,
- REDACTION_TYPE_NONE);
- Notification.Builder builder = spy(mBuilder);
- mNotificationInflater.inflateNotificationViews(
- mRow.getEntry(),
- mRow,
- params,
- true /* inflateSynchronously */,
- FLAG_CONTENT_VIEW_ALL,
- builder,
- mContext,
- mContext,
- mSmartReplyStateInflater);
- verify(builder).createContentView(true);
- }
-
- @Test
public void testInflationCallsUpdated() throws Exception {
inflateAndWait(mNotificationInflater, FLAG_CONTENT_VIEW_ALL, mRow);
verify(mRow).onNotificationUpdated();
@@ -238,7 +202,7 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
mRow.getEntry(),
mRow,
FLAG_CONTENT_VIEW_ALL,
- new BindParams(false, false, false, REDACTION_TYPE_NONE),
+ new BindParams(false, REDACTION_TYPE_NONE),
false /* forceInflate */,
null /* callback */);
Assert.assertNull(mRow.getEntry().getRunningTask());
@@ -576,7 +540,7 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
row.getEntry(),
row,
contentToInflate,
- new BindParams(false, false, false, redactionType),
+ new BindParams(false, redactionType),
false /* forceInflate */,
callback /* callback */);
assertTrue(countDownLatch.await(500, TimeUnit.MILLISECONDS));
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt
index f25ba2c93c65..680b1bee72b2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt
@@ -144,43 +144,6 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() {
}
@Test
- fun testIncreasedHeadsUpBeingUsed() {
- val params =
- BindParams(false, false, /* usesIncreasedHeadsUpHeight */ true, REDACTION_TYPE_NONE)
- val builder = spy(builder)
- notificationInflater.inflateNotificationViews(
- row.entry,
- row,
- params,
- true, /* inflateSynchronously */
- FLAG_CONTENT_VIEW_ALL,
- builder,
- mContext,
- smartReplyStateInflater,
- mock(),
- )
- verify(builder).createHeadsUpContentView(true)
- }
-
- @Test
- fun testIncreasedHeightBeingUsed() {
- val params = BindParams(false, /* usesIncreasedHeight */ true, false, REDACTION_TYPE_NONE)
- val builder = spy(builder)
- notificationInflater.inflateNotificationViews(
- row.entry,
- row,
- params,
- true, /* inflateSynchronously */
- FLAG_CONTENT_VIEW_ALL,
- builder,
- mContext,
- smartReplyStateInflater,
- mock(),
- )
- verify(builder).createContentView(true)
- }
-
- @Test
fun testInflationCallsUpdated() {
inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_ALL, row)
verify(row).onNotificationUpdated()
@@ -226,7 +189,7 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() {
row.entry,
row,
FLAG_CONTENT_VIEW_ALL,
- BindParams(false, false, false, REDACTION_TYPE_NONE),
+ BindParams(false, REDACTION_TYPE_NONE),
false, /* forceInflate */
null, /* callback */
)
@@ -703,7 +666,7 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() {
row.entry,
row,
contentToInflate,
- BindParams(false, false, false, redactionType),
+ BindParams(false, redactionType),
false, /* forceInflate */
callback, /* callback */
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
index 841cb4a3669b..98e275a473fa 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
@@ -214,54 +214,6 @@ public class RowContentBindStageTest extends SysuiTestCase {
}
@Test
- public void testSetUseIncreasedHeight() {
- // GIVEN a view with all content bound.
- RowContentBindParams params = mRowContentBindStage.getStageParams(mEntry);
- params.requireContentViews(FLAG_CONTENT_VIEW_ALL);
- params.clearDirtyContentViews();
-
- // WHEN use increased height is set and stage executed.
- params.setUseIncreasedCollapsedHeight(true);
- mRowContentBindStage.executeStage(mEntry, mRow, (en) -> { });
-
- // THEN binder is called with group view and contracted is bound.
- ArgumentCaptor<BindParams> bindParamsCaptor = ArgumentCaptor.forClass(BindParams.class);
- verify(mBinder).bindContent(
- eq(mEntry),
- any(),
- eq(FLAG_CONTENT_VIEW_CONTRACTED),
- bindParamsCaptor.capture(),
- anyBoolean(),
- any());
- BindParams usedParams = bindParamsCaptor.getValue();
- assertTrue(usedParams.usesIncreasedHeight);
- }
-
- @Test
- public void testSetUseIncreasedHeadsUpHeight() {
- // GIVEN a view with all content bound.
- RowContentBindParams params = mRowContentBindStage.getStageParams(mEntry);
- params.requireContentViews(FLAG_CONTENT_VIEW_ALL);
- params.clearDirtyContentViews();
-
- // WHEN use increased heads up height is set and stage executed.
- params.setUseIncreasedHeadsUpHeight(true);
- mRowContentBindStage.executeStage(mEntry, mRow, (en) -> { });
-
- // THEN binder is called with use group view and heads up is bound.
- ArgumentCaptor<BindParams> bindParamsCaptor = ArgumentCaptor.forClass(BindParams.class);
- verify(mBinder).bindContent(
- eq(mEntry),
- any(),
- eq(FLAG_CONTENT_VIEW_HEADS_UP),
- bindParamsCaptor.capture(),
- anyBoolean(),
- any());
- BindParams usedParams = bindParamsCaptor.getValue();
- assertTrue(usedParams.usesIncreasedHeadsUpHeight);
- }
-
- @Test
public void testSetNeedsReinflation() {
// GIVEN a view with all content bound.
RowContentBindParams params = mRowContentBindStage.getStageParams(mEntry);
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 06a2c5af2986..66ccf1822e21 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
@@ -25,6 +25,7 @@ import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimRounding
+import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
@@ -40,28 +41,39 @@ class NotificationStackAppearanceInteractorTest : SysuiTestCase() {
private val underTest = kosmos.notificationStackAppearanceInteractor
@Test
- fun stackBounds() =
+ fun stackNotificationScrimBounds() =
testScope.runTest {
- val stackBounds by collectLastValue(underTest.shadeScrimBounds)
+ val stackBounds by collectLastValue(underTest.notificationShadeScrimBounds)
- val bounds1 =
- ShadeScrimBounds(
- top = 100f,
- bottom = 200f,
- )
- underTest.setShadeScrimBounds(bounds1)
+ val bounds1 = ShadeScrimBounds(top = 100f, bottom = 200f)
+ underTest.setNotificationShadeScrimBounds(bounds1)
assertThat(stackBounds).isEqualTo(bounds1)
- val bounds2 =
- ShadeScrimBounds(
- top = 200f,
- bottom = 300f,
- )
- underTest.setShadeScrimBounds(bounds2)
+ val bounds2 = ShadeScrimBounds(top = 200f, bottom = 300f)
+ underTest.setNotificationShadeScrimBounds(bounds2)
assertThat(stackBounds).isEqualTo(bounds2)
}
@Test
+ fun setQsPanelShape() =
+ testScope.runTest {
+ val actual by collectLastValue(underTest.qsPanelShape)
+
+ val expected1 =
+ ShadeScrimShape(
+ bounds = ShadeScrimBounds(top = 0f, bottom = 100f),
+ topRadius = 0,
+ bottomRadius = 10,
+ )
+ underTest.setQsPanelShape(expected1)
+ assertThat(actual).isEqualTo(expected1)
+
+ val expected2 = expected1.copy(topRadius = 10)
+ underTest.setQsPanelShape(expected2)
+ assertThat(expected2).isEqualTo(actual)
+ }
+
+ @Test
fun stackRounding() =
testScope.runTest {
val stackRounding by collectLastValue(underTest.shadeScrimRounding)
@@ -76,13 +88,17 @@ class NotificationStackAppearanceInteractorTest : SysuiTestCase() {
}
@Test(expected = IllegalStateException::class)
- fun setStackBounds_withImproperBounds_throwsException() =
+ fun stackNotificationScrimBounds_withImproperBounds_throwsException() =
testScope.runTest {
- underTest.setShadeScrimBounds(
- ShadeScrimBounds(
- top = 100f,
- bottom = 99f,
- )
+ underTest.setNotificationShadeScrimBounds(ShadeScrimBounds(top = 100f, bottom = 99f))
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun setQsPanelShape_withImproperBounds_throwsException() =
+ testScope.runTest {
+ val invalidBounds = ShadeScrimBounds(top = 0f, bottom = -10f)
+ underTest.setQsPanelShape(
+ ShadeScrimShape(bounds = invalidBounds, topRadius = 10, bottomRadius = 10)
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt
index 4944c8bd0221..14e7cdc50227 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt
@@ -38,12 +38,14 @@ class NotificationsPlaceholderViewModelTest : SysuiTestCase() {
private val underTest by lazy { kosmos.notificationsPlaceholderViewModel }
@Test
- fun onBoundsChanged() =
+ fun onScrimBoundsChanged() =
kosmos.testScope.runTest {
val bounds = ShadeScrimBounds(left = 5f, top = 15f, right = 25f, bottom = 35f)
underTest.onScrimBoundsChanged(bounds)
val stackBounds by
- collectLastValue(kosmos.notificationStackAppearanceInteractor.shadeScrimBounds)
+ collectLastValue(
+ kosmos.notificationStackAppearanceInteractor.notificationShadeScrimBounds
+ )
assertThat(stackBounds).isEqualTo(bounds)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.kt
index 216f51d992d0..bd76268d2cfa 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.kt
@@ -34,6 +34,7 @@ import com.android.systemui.shade.shadeViewController
import com.android.systemui.statusbar.HeadsUpStatusBarView
import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
import com.android.systemui.statusbar.commandQueue
+import com.android.systemui.statusbar.headsup.shared.StatusBarNoHunBehavior
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor
import com.android.systemui.statusbar.notification.domain.interactor.headsUpNotificationIconInteractor
@@ -118,6 +119,7 @@ class HeadsUpAppearanceControllerTest : SysuiTestCase() {
}
@Test
+ @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
fun showingEntryUpdated_whenPinnedBySystem() {
row.setPinnedStatus(PinnedStatus.PinnedBySystem)
setHeadsUpNotifOnManager(entry)
@@ -133,8 +135,18 @@ class HeadsUpAppearanceControllerTest : SysuiTestCase() {
}
@Test
- @DisableFlags(StatusBarNotifChips.FLAG_NAME)
- fun showingEntryUpdated_whenPinnedByUser_andFlagOff() {
+ @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+ fun showingEntryNotUpdated_whenPinnedBySystem_whenNoHunBehaviorEnabled() {
+ row.setPinnedStatus(PinnedStatus.PinnedBySystem)
+ setHeadsUpNotifOnManager(entry)
+ underTest.onHeadsUpPinned(entry)
+
+ assertThat(headsUpStatusBarView.showingEntry).isNull()
+ }
+
+ @Test
+ @DisableFlags(StatusBarNotifChips.FLAG_NAME, StatusBarNoHunBehavior.FLAG_NAME)
+ fun showingEntryUpdated_whenPinnedByUser_andNotifChipsFlagOff() {
row.setPinnedStatus(PinnedStatus.PinnedByUser)
setHeadsUpNotifOnManager(entry)
underTest.onHeadsUpPinned(entry)
@@ -144,7 +156,7 @@ class HeadsUpAppearanceControllerTest : SysuiTestCase() {
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun showingEntryNotUpdated_whenPinnedByUser_andFlagOn() {
+ fun showingEntryNotUpdated_whenPinnedByUser_andNotifChipsFlagOn() {
// WHEN the HUN was pinned by the user
row.setPinnedStatus(PinnedStatus.PinnedByUser)
setHeadsUpNotifOnManager(entry)
@@ -155,6 +167,7 @@ class HeadsUpAppearanceControllerTest : SysuiTestCase() {
}
@Test
+ @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
fun pinnedStatusUpdatedToSystem_whenPinnedBySystem() {
row.setPinnedStatus(PinnedStatus.PinnedBySystem)
setHeadsUpNotifOnManager(entry)
@@ -168,8 +181,19 @@ class HeadsUpAppearanceControllerTest : SysuiTestCase() {
}
@Test
+ @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+ fun pinnedStatusNotUpdatedToSystem_whenPinnedBySystem_whenNoHunBehaviorEnabled() {
+ row.setPinnedStatus(PinnedStatus.PinnedBySystem)
+ setHeadsUpNotifOnManager(entry)
+ underTest.onHeadsUpPinned(entry)
+
+ assertThat(underTest.pinnedStatus).isEqualTo(PinnedStatus.NotPinned)
+ }
+
+ @Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun pinnedStatusUpdatedToNotPinned_whenPinnedByUser_andFlagOn() {
+ @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+ fun pinnedStatusUpdatedToNotPinned_whenPinnedByUser_andNotifChipsFlagOn() {
row.setPinnedStatus(PinnedStatus.PinnedByUser)
setHeadsUpNotifOnManager(entry)
underTest.onHeadsUpPinned(entry)
@@ -182,6 +206,7 @@ class HeadsUpAppearanceControllerTest : SysuiTestCase() {
}
@Test
+ @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
fun isolatedIconSet_whenPinnedBySystem() =
kosmos.runTest {
val latestIsolatedIcon by
@@ -201,8 +226,22 @@ class HeadsUpAppearanceControllerTest : SysuiTestCase() {
}
@Test
- @DisableFlags(StatusBarNotifChips.FLAG_NAME)
- fun isolatedIconSet_whenPinnedByUser_andFlagOff() =
+ @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+ fun isolatedIconNotSet_whenPinnedBySystem_whenNoHunBehaviorEnabled() =
+ kosmos.runTest {
+ val latestIsolatedIcon by
+ collectLastValue(kosmos.headsUpNotificationIconInteractor.isolatedNotification)
+
+ row.setPinnedStatus(PinnedStatus.PinnedBySystem)
+ setHeadsUpNotifOnManager(entry)
+ underTest.onHeadsUpPinned(entry)
+
+ assertThat(latestIsolatedIcon).isNull()
+ }
+
+ @Test
+ @DisableFlags(StatusBarNotifChips.FLAG_NAME, StatusBarNoHunBehavior.FLAG_NAME)
+ fun isolatedIconSet_whenPinnedByUser_andNotifChipsFlagOff() =
kosmos.runTest {
val latestIsolatedIcon by
collectLastValue(kosmos.headsUpNotificationIconInteractor.isolatedNotification)
@@ -216,7 +255,7 @@ class HeadsUpAppearanceControllerTest : SysuiTestCase() {
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun isolatedIconNotSet_whenPinnedByUser_andFlagOn() =
+ fun isolatedIconNotSet_whenPinnedByUser_andNotifChipsFlagOn() =
kosmos.runTest {
val latestIsolatedIcon by
collectLastValue(kosmos.headsUpNotificationIconInteractor.isolatedNotification)
@@ -243,6 +282,7 @@ class HeadsUpAppearanceControllerTest : SysuiTestCase() {
}
@Test
+ @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
fun operatorNameViewUpdated_whenPinnedBySystem() {
underTest.setAnimationsEnabled(false)
@@ -258,8 +298,20 @@ class HeadsUpAppearanceControllerTest : SysuiTestCase() {
}
@Test
- @DisableFlags(StatusBarNotifChips.FLAG_NAME)
- fun operatorNameViewUpdated_whenPinnedByUser_andFlagOff() {
+ @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+ fun operatorNameViewNotUpdated_whenPinnedBySystem_whenNoHunBehaviorEnabled() {
+ underTest.setAnimationsEnabled(false)
+
+ row.setPinnedStatus(PinnedStatus.PinnedBySystem)
+ setHeadsUpNotifOnManager(entry)
+ underTest.onHeadsUpPinned(entry)
+
+ assertThat(operatorNameView.visibility).isEqualTo(View.VISIBLE)
+ }
+
+ @Test
+ @DisableFlags(StatusBarNotifChips.FLAG_NAME, StatusBarNoHunBehavior.FLAG_NAME)
+ fun operatorNameViewUpdated_whenPinnedByUser_andNotifChipsFlagOff() {
underTest.setAnimationsEnabled(false)
row.setPinnedStatus(PinnedStatus.PinnedByUser)
@@ -271,7 +323,7 @@ class HeadsUpAppearanceControllerTest : SysuiTestCase() {
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun operatorNameViewNotUpdated_whenPinnedByUser_andFlagOn() {
+ fun operatorNameViewNotUpdated_whenPinnedByUser_andNotifChipsFlagOn() {
underTest.setAnimationsEnabled(false)
// WHEN the row was pinned by the user
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
index 650fa7ce46de..58856d970711 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DIALOG_SHOWING;
+
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertFalse;
@@ -44,7 +46,9 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogTransitionAnimator;
import com.android.systemui.animation.back.BackAnimationSpec;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.model.SysUiState;
+import com.android.systemui.settings.FakeDisplayTracker;
import org.junit.Before;
import org.junit.Rule;
@@ -68,6 +72,7 @@ public class SystemUIDialogTest extends SysuiTestCase {
private BroadcastDispatcher mBroadcastDispatcher;
@Mock
private SystemUIDialog.Delegate mDelegate;
+ private SysUiState mSysUiState;
// TODO(b/292141694): build out Ravenwood support for DeviceFlagsValueProvider
// Ravenwood already has solid support for SetFlagsRule, but CheckFlagsRule will be added soon
@@ -78,7 +83,9 @@ public class SystemUIDialogTest extends SysuiTestCase {
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
-
+ KosmosJavaAdapter kosmos = new KosmosJavaAdapter(this);
+ FakeDisplayTracker displayTracker = new FakeDisplayTracker(mContext);
+ mSysUiState = new SysUiState(displayTracker, kosmos.getSceneContainerPlugin());
mDependency.injectTestDependency(BroadcastDispatcher.class, mBroadcastDispatcher);
when(mDelegate.getBackAnimationSpec(ArgumentMatchers.any()))
.thenReturn(mock(BackAnimationSpec.class));
@@ -173,6 +180,30 @@ public class SystemUIDialogTest extends SysuiTestCase {
assertThat(calledStop.get()).isTrue();
}
+ /** Regression test for b/386871258 */
+ @Test
+ public void sysuiStateUpdated() {
+ SystemUIDialog dialog1 =
+ createDialogWithDelegate(mContext, mDelegate, /* shouldAcsDismissDialog */ true);
+ SystemUIDialog dialog2 =
+ createDialogWithDelegate(mContext, mDelegate, /* shouldAcsDismissDialog */ true);
+
+ dialog1.show();
+ assertThat((mSysUiState.getFlags() & SYSUI_STATE_DIALOG_SHOWING) != 0).isTrue();
+
+ dialog2.show();
+ assertThat((mSysUiState.getFlags() & SYSUI_STATE_DIALOG_SHOWING) != 0).isTrue();
+
+ dialog2.dismiss();
+ // explicitly call onWindowFocusChanged to simulate dialog 1 regaining focus
+ dialog1.onWindowFocusChanged(/* hasFocus= */ true);
+ assertThat((mSysUiState.getFlags() & SYSUI_STATE_DIALOG_SHOWING) != 0).isTrue();
+
+ dialog1.dismiss();
+ assertThat((mSysUiState.getFlags() & SYSUI_STATE_DIALOG_SHOWING) != 0).isFalse();
+ }
+
+
@Test
public void delegateIsCalled_inCorrectOrder() {
Configuration configuration = new Configuration();
@@ -198,7 +229,7 @@ public class SystemUIDialogTest extends SysuiTestCase {
SystemUIDialog.Factory factory = new SystemUIDialog.Factory(
getContext(),
Dependency.get(SystemUIDialogManager.class),
- Dependency.get(SysUiState.class),
+ mSysUiState,
Dependency.get(BroadcastDispatcher.class),
Dependency.get(DialogTransitionAnimator.class)
);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index 6da06a36f63d..02135f6a7836 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -41,6 +41,7 @@ import com.android.systemui.statusbar.notification.data.model.activeNotification
import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
import com.android.systemui.statusbar.notification.shared.CallType
import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository
@@ -169,6 +170,27 @@ class OngoingCallControllerTest : SysuiTestCase() {
}
@Test
+ fun interactorHasOngoingCallNotif_repoHasPromotedContent() =
+ testScope.runTest {
+ val promotedContent = PromotedNotificationContentModel.Builder("ongoingNotif").build()
+ setNotifOnRepo(
+ activeNotificationModel(
+ key = "ongoingNotif",
+ callType = CallType.Ongoing,
+ uid = CALL_UID,
+ statusBarChipIcon = mock(),
+ whenTime = 567,
+ promotedContent = promotedContent,
+ )
+ )
+
+ val repoState = ongoingCallRepository.ongoingCallState.value
+ assertThat(repoState).isInstanceOf(OngoingCallModel.InCall::class.java)
+ assertThat((repoState as OngoingCallModel.InCall).promotedContent)
+ .isEqualTo(promotedContent)
+ }
+
+ @Test
fun notifRepoHasOngoingCallNotif_isOngoingCallNotif_windowControllerUpdated() {
setCallNotifOnRepo()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt
index 8fb95e843ec1..14263c4b1b9b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt
@@ -35,6 +35,7 @@ import com.android.systemui.statusbar.gesture.swipeStatusBarAwayGestureHandler
import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
import com.android.systemui.statusbar.notification.shared.CallType
import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
import com.android.systemui.statusbar.window.fakeStatusBarWindowControllerStore
@@ -69,33 +70,37 @@ class OngoingCallInteractorTest : SysuiTestCase() {
}
@Test
- fun ongoingCallNotification_setsNotificationIconAndIntent() =
+ fun ongoingCallNotification_setsAllFields() =
kosmos.runTest {
val latest by collectLastValue(underTest.ongoingCallState)
// Set up notification with icon view and intent
val testIconView: StatusBarIconView = mock()
val testIntent: PendingIntent = mock()
+ val testPromotedContent =
+ PromotedNotificationContentModel.Builder("promotedCall").build()
repository.activeNotifications.value =
ActiveNotificationsStore.Builder()
.apply {
addIndividualNotif(
activeNotificationModel(
- key = "notif1",
+ key = "promotedCall",
whenTime = 1000L,
callType = CallType.Ongoing,
statusBarChipIcon = testIconView,
contentIntent = testIntent,
+ promotedContent = testPromotedContent,
)
)
}
.build()
- // Verify model is InCall and has the correct icon and intent.
+ // Verify model is InCall and has the correct icon, intent, and promoted content.
assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java)
val model = latest as OngoingCallModel.InCall
assertThat(model.notificationIconView).isSameInstanceAs(testIconView)
assertThat(model.intent).isSameInstanceAs(testIntent)
+ assertThat(model.promotedContent).isSameInstanceAs(testPromotedContent)
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt
index 6feada1c9769..937f333b0065 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt
@@ -46,6 +46,8 @@ class FakeHomeStatusBarViewModel(
override val isHomeStatusBarAllowedByScene = MutableStateFlow(false)
+ override val shouldHomeStatusBarBeVisible = MutableStateFlow(false)
+
override val shouldShowOperatorNameView = MutableStateFlow(false)
override val isClockVisible =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
index e95bc3378423..03abcf850d26 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
@@ -70,6 +70,7 @@ import com.android.systemui.statusbar.events.data.repository.systemStatusEventAn
import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.AnimatingIn
import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.AnimatingOut
import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.Idle
+import com.android.systemui.statusbar.headsup.shared.StatusBarNoHunBehavior
import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
import com.android.systemui.statusbar.notification.data.repository.UnconfinedFakeHeadsUpRowRepository
@@ -552,9 +553,10 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {
}
@Test
- fun shouldShowOperatorNameView_allowedByInteractor_hunPinned_false() =
+ @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+ fun shouldShowOperatorNameView_allowedByInteractor_hunPinned_noHunBehaviorFlagOff_false() =
kosmos.runTest {
- kosmos.setHomeStatusBarInteractorShowOperatorName(false)
+ kosmos.setHomeStatusBarInteractorShowOperatorName(true)
transitionKeyguardToGone()
@@ -565,7 +567,7 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {
headsUpNotificationRepository.setNotifications(
UnconfinedFakeHeadsUpRowRepository(
key = "key",
- pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser),
+ pinnedStatus = MutableStateFlow(PinnedStatus.PinnedBySystem),
)
)
@@ -575,6 +577,123 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {
}
@Test
+ @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+ fun shouldShowOperatorNameView_allowedByInteractor_hunPinned_noHunBehaviorFlagOn_true() =
+ kosmos.runTest {
+ kosmos.setHomeStatusBarInteractorShowOperatorName(true)
+
+ transitionKeyguardToGone()
+
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)
+
+ // WHEN there is an active HUN
+ headsUpNotificationRepository.setNotifications(
+ UnconfinedFakeHeadsUpRowRepository(
+ key = "key",
+ pinnedStatus = MutableStateFlow(PinnedStatus.PinnedBySystem),
+ )
+ )
+
+ val latest by collectLastValue(underTest.shouldShowOperatorNameView)
+
+ // THEN we still show the operator name view if NoHunBehavior flag is enabled
+ assertThat(latest).isTrue()
+ }
+
+ @Test
+ fun shouldHomeStatusBarBeVisible_keyguardNotGone_noHun_false() =
+ kosmos.runTest {
+ // Do not transition from keyguard. i.e., we don't call transitionKeyguardToGone()
+
+ // Nothing disabled
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)
+
+ val latest by collectLastValue(underTest.shouldHomeStatusBarBeVisible)
+ assertThat(latest).isFalse()
+ }
+
+ @Test
+ fun shouldHomeStatusBarBeVisible_keyguardNotGone_hun_true() =
+ kosmos.runTest {
+ // Keyguard gone
+ transitionKeyguardToGone()
+
+ // Nothing disabled
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)
+
+ // there is an active HUN
+ headsUpNotificationRepository.setNotifications(
+ UnconfinedFakeHeadsUpRowRepository(
+ key = "key",
+ pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser),
+ )
+ )
+
+ val latest by collectLastValue(underTest.shouldHomeStatusBarBeVisible)
+ assertThat(latest).isTrue()
+ }
+
+ @Test
+ fun shouldHomeStatusBarBeVisible_keyguardGone_noHun_notInCamera_true() =
+ kosmos.runTest {
+ // Keyguard gone
+ transitionKeyguardToGone()
+
+ // Nothing disabled
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)
+
+ val latest by collectLastValue(underTest.shouldHomeStatusBarBeVisible)
+ assertThat(latest).isTrue()
+ }
+
+ @Test
+ fun shouldHomeStatusBarBeVisible_keyguardGone_hun_notInCamera_true() =
+ kosmos.runTest {
+ // Keyguard gone
+ transitionKeyguardToGone()
+
+ // Nothing disabled
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)
+
+ // there is an active HUN
+ headsUpNotificationRepository.setNotifications(
+ UnconfinedFakeHeadsUpRowRepository(
+ key = "key",
+ pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser),
+ )
+ )
+
+ val latest by collectLastValue(underTest.shouldHomeStatusBarBeVisible)
+ assertThat(latest).isTrue()
+ }
+
+ @Test
+ fun shouldHomeStatusBarBeVisible_keyguardGone_noHun_inCamera_false() =
+ kosmos.runTest {
+ // Keyguard gone
+ transitionKeyguardToGone()
+
+ // Nothing disabled
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)
+
+ fakeKeyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.OCCLUDED,
+ testScope = testScope,
+ )
+ kosmos.keyguardInteractor.onCameraLaunchDetected(CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP)
+
+ val latest by collectLastValue(underTest.shouldHomeStatusBarBeVisible)
+ assertThat(latest).isFalse()
+ }
+
+ @Test
fun isClockVisible_allowedByDisableFlags_visible() =
kosmos.runTest {
val latest by collectLastValue(underTest.isClockVisible)
@@ -600,7 +719,7 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun isClockVisible_allowedByFlags_hunPinnedByUser_visible() =
+ fun isClockVisible_allowedByDisableFlags_hunPinnedByUser_visible() =
kosmos.runTest {
val latest by collectLastValue(underTest.isClockVisible)
transitionKeyguardToGone()
@@ -619,7 +738,8 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {
}
@Test
- fun isClockVisible_allowedByFlags_hunPinnedBySystem_notVisible() =
+ @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+ fun isClockVisible_allowedByDisableFlags_hunPinnedBySystem_noHunBehaviorFlagOff_notVisible() =
kosmos.runTest {
val latest by collectLastValue(underTest.isClockVisible)
transitionKeyguardToGone()
@@ -638,7 +758,29 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {
}
@Test
- fun isClockVisible_allowedByFlags_hunBecomesInactive_visibleAgain() =
+ @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+ fun isClockVisible_allowedByDisableFlags_hunPinnedBySystem_noHunBehaviorFlagOn_visible() =
+ kosmos.runTest {
+ val latest by collectLastValue(underTest.isClockVisible)
+ transitionKeyguardToGone()
+
+ fakeDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)
+ // WHEN there is an active HUN
+ headsUpNotificationRepository.setNotifications(
+ UnconfinedFakeHeadsUpRowRepository(
+ key = "key",
+ pinnedStatus = MutableStateFlow(PinnedStatus.PinnedBySystem),
+ )
+ )
+
+ // THEN we still show the clock view if NoHunBehavior flag is enabled
+ assertThat(latest!!.visibility).isEqualTo(View.VISIBLE)
+ }
+
+ @Test
+ @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+ fun isClockVisible_allowedByDisableFlags_hunBecomesInactive_visibleAgain() =
kosmos.runTest {
val latest by collectLastValue(underTest.isClockVisible)
transitionKeyguardToGone()
@@ -661,7 +803,8 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {
}
@Test
- fun isClockVisible_disabledByFlags_hunBecomesInactive_neverVisible() =
+ @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+ fun isClockVisible_disableFlagsProhibitClock_hunBecomesInactive_neverVisible() =
kosmos.runTest {
val latest by collectLastValue(underTest.isClockVisible)
transitionKeyguardToGone()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/StatusBarOperatorNameViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/StatusBarOperatorNameViewModelTest.kt
index 20cc85f08b01..8608b0bf2f0b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/StatusBarOperatorNameViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/StatusBarOperatorNameViewModelTest.kt
@@ -39,14 +39,12 @@ class StatusBarOperatorNameViewModelTest : SysuiTestCase() {
kosmos.runTest {
val intr1 = fakeMobileIconsInteractor.getMobileConnectionInteractorForSubId(1)
val intr2 = fakeMobileIconsInteractor.getMobileConnectionInteractorForSubId(2)
- val invalidIntr = fakeMobileIconsInteractor.getMobileConnectionInteractorForSubId(-1)
// GIVEN default data subId is 1
fakeMobileIconsInteractor.defaultDataSubId.value = 1
intr1.carrierName.value = "Test Name 1"
intr2.carrierName.value = "Test Name 2"
- invalidIntr.carrierName.value = "default network name"
val latest by collectLastValue(underTest.operatorName)
@@ -56,8 +54,19 @@ class StatusBarOperatorNameViewModelTest : SysuiTestCase() {
assertThat(latest).isEqualTo("Test Name 2")
- fakeMobileIconsInteractor.defaultDataSubId.value = -1
+ fakeMobileIconsInteractor.defaultDataSubId.value = null
- assertThat(latest).isEqualTo("default network name")
+ assertThat(latest).isNull()
+ }
+
+ @Test
+ fun operatorName_noDefaultDataSubId_null() =
+ kosmos.runTest {
+ // GIVEN defaultDataSubId is null
+ fakeMobileIconsInteractor.defaultDataSubId.value = null
+
+ val latest by collectLastValue(underTest.operatorName)
+
+ assertThat(latest).isNull()
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt
index 7802b921eae0..ff1ffccfb2de 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt
@@ -36,8 +36,9 @@ import com.android.settingslib.notification.modes.TestModeBuilder
import com.android.settingslib.notification.modes.TestModeBuilder.MANUAL_DND
import com.android.settingslib.volume.shared.model.AudioStream
import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.shared.settings.data.repository.secureSettingsRepository
import com.android.systemui.statusbar.notification.emptyshade.shared.ModesEmptyShadeFix
import com.android.systemui.statusbar.policy.data.repository.fakeDeviceProvisioningRepository
@@ -45,186 +46,151 @@ import com.android.systemui.statusbar.policy.data.repository.fakeZenModeReposito
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import java.time.Duration
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
-@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
@SmallTest
class ZenModeInteractorTest : SysuiTestCase() {
- private val kosmos = testKosmos()
- private val testScope = kosmos.testScope
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
private val zenModeRepository = kosmos.fakeZenModeRepository
private val settingsRepository = kosmos.secureSettingsRepository
private val deviceProvisioningRepository = kosmos.fakeDeviceProvisioningRepository
- private val underTest = kosmos.zenModeInteractor
+ private val underTest by lazy { kosmos.zenModeInteractor }
@Test
fun isZenAvailable_off() =
- testScope.runTest {
+ kosmos.runTest {
val isZenAvailable by collectLastValue(underTest.isZenAvailable)
deviceProvisioningRepository.setDeviceProvisioned(false)
- runCurrent()
-
assertThat(isZenAvailable).isFalse()
}
@Test
fun isZenAvailable_on() =
- testScope.runTest {
+ kosmos.runTest {
val isZenAvailable by collectLastValue(underTest.isZenAvailable)
deviceProvisioningRepository.setDeviceProvisioned(true)
- runCurrent()
-
assertThat(isZenAvailable).isTrue()
}
@Test
fun isZenModeEnabled_off() =
- testScope.runTest {
+ kosmos.runTest {
val enabled by collectLastValue(underTest.isZenModeEnabled)
-
zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_OFF)
- runCurrent()
-
assertThat(enabled).isFalse()
}
@Test
fun isZenModeEnabled_alarms() =
- testScope.runTest {
+ kosmos.runTest {
val enabled by collectLastValue(underTest.isZenModeEnabled)
-
zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_ALARMS)
- runCurrent()
-
assertThat(enabled).isTrue()
}
@Test
fun isZenModeEnabled_importantInterruptions() =
- testScope.runTest {
+ kosmos.runTest {
val enabled by collectLastValue(underTest.isZenModeEnabled)
-
zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
- runCurrent()
-
assertThat(enabled).isTrue()
}
@Test
fun isZenModeEnabled_noInterruptions() =
- testScope.runTest {
+ kosmos.runTest {
val enabled by collectLastValue(underTest.isZenModeEnabled)
-
zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS)
- runCurrent()
-
assertThat(enabled).isTrue()
}
@Test
fun testIsZenModeEnabled_unknown() =
- testScope.runTest {
+ kosmos.runTest {
val enabled by collectLastValue(underTest.isZenModeEnabled)
-
// this should fail if we ever add another zen mode type
zenModeRepository.updateZenMode(4)
- runCurrent()
-
assertThat(enabled).isFalse()
}
@Test
fun areNotificationsHiddenInShade_noPolicy() =
- testScope.runTest {
+ kosmos.runTest {
val hidden by collectLastValue(underTest.areNotificationsHiddenInShade)
zenModeRepository.updateNotificationPolicy(null)
zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
- runCurrent()
assertThat(hidden).isFalse()
}
@Test
fun areNotificationsHiddenInShade_zenOffShadeSuppressed() =
- testScope.runTest {
+ kosmos.runTest {
val hidden by collectLastValue(underTest.areNotificationsHiddenInShade)
zenModeRepository.updateNotificationPolicy(
suppressedVisualEffects = Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST
)
zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_OFF)
- runCurrent()
assertThat(hidden).isFalse()
}
@Test
fun areNotificationsHiddenInShade_zenOnShadeNotSuppressed() =
- testScope.runTest {
+ kosmos.runTest {
val hidden by collectLastValue(underTest.areNotificationsHiddenInShade)
zenModeRepository.updateNotificationPolicy(
suppressedVisualEffects = Policy.SUPPRESSED_EFFECT_STATUS_BAR
)
zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
- runCurrent()
assertThat(hidden).isFalse()
}
@Test
fun areNotificationsHiddenInShade_zenOnShadeSuppressed() =
- testScope.runTest {
+ kosmos.runTest {
val hidden by collectLastValue(underTest.areNotificationsHiddenInShade)
zenModeRepository.updateNotificationPolicy(
suppressedVisualEffects = Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST
)
zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
- runCurrent()
assertThat(hidden).isTrue()
}
@Test
fun shouldAskForZenDuration_falseForNonManualDnd() =
- testScope.runTest {
+ kosmos.runTest {
settingsRepository.setInt(ZEN_DURATION, ZEN_DURATION_PROMPT)
- runCurrent()
-
assertThat(underTest.shouldAskForZenDuration(TestModeBuilder.EXAMPLE)).isFalse()
}
@Test
fun shouldAskForZenDuration_changesWithSetting() =
- testScope.runTest {
- val manualDnd = TestModeBuilder().makeManualDnd().setActive(true).build()
+ kosmos.runTest {
+ val manualDnd by collectLastValue(underTest.dndMode)
settingsRepository.setInt(ZEN_DURATION, ZEN_DURATION_FOREVER)
- runCurrent()
-
- assertThat(underTest.shouldAskForZenDuration(manualDnd)).isFalse()
+ assertThat(underTest.shouldAskForZenDuration(manualDnd!!)).isFalse()
settingsRepository.setInt(ZEN_DURATION, ZEN_DURATION_PROMPT)
- runCurrent()
-
- assertThat(underTest.shouldAskForZenDuration(manualDnd)).isTrue()
+ assertThat(underTest.shouldAskForZenDuration(manualDnd!!)).isTrue()
}
@Test
fun activateMode_nonManualDnd() =
- testScope.runTest {
+ kosmos.runTest {
val mode = TestModeBuilder().setActive(false).build()
zenModeRepository.addModes(listOf(mode))
settingsRepository.setInt(ZEN_DURATION, 60)
- runCurrent()
underTest.activateMode(mode)
assertThat(zenModeRepository.getMode(mode.id)?.isActive).isTrue()
@@ -233,16 +199,14 @@ class ZenModeInteractorTest : SysuiTestCase() {
@Test
fun activateMode_usesCorrectDuration() =
- testScope.runTest {
+ kosmos.runTest {
settingsRepository.setInt(ZEN_DURATION, ZEN_DURATION_FOREVER)
- runCurrent()
underTest.activateMode(MANUAL_DND)
assertThat(zenModeRepository.getModeActiveDuration(MANUAL_DND.id)).isNull()
zenModeRepository.deactivateMode(MANUAL_DND)
settingsRepository.setInt(ZEN_DURATION, 60)
- runCurrent()
underTest.activateMode(MANUAL_DND)
assertThat(zenModeRepository.getModeActiveDuration(MANUAL_DND.id))
@@ -251,7 +215,7 @@ class ZenModeInteractorTest : SysuiTestCase() {
@Test
fun deactivateAllModes_updatesCorrectModes() =
- testScope.runTest {
+ kosmos.runTest {
zenModeRepository.activateMode(MANUAL_DND)
zenModeRepository.addModes(
listOf(
@@ -267,72 +231,69 @@ class ZenModeInteractorTest : SysuiTestCase() {
@Test
fun activeModes_computesMainActiveMode() =
- testScope.runTest {
+ kosmos.runTest {
val activeModes by collectLastValue(underTest.activeModes)
zenModeRepository.addMode(id = "Bedtime", type = AutomaticZenRule.TYPE_BEDTIME)
zenModeRepository.addMode(id = "Other", type = AutomaticZenRule.TYPE_OTHER)
-
- runCurrent()
assertThat(activeModes?.modeNames).hasSize(0)
assertThat(activeModes?.mainMode).isNull()
zenModeRepository.activateMode("Other")
- runCurrent()
assertThat(activeModes?.modeNames).containsExactly("Mode Other")
assertThat(activeModes?.mainMode?.name).isEqualTo("Mode Other")
zenModeRepository.activateMode("Bedtime")
- runCurrent()
assertThat(activeModes?.modeNames)
.containsExactly("Mode Bedtime", "Mode Other")
.inOrder()
assertThat(activeModes?.mainMode?.name).isEqualTo("Mode Bedtime")
zenModeRepository.deactivateMode("Other")
- runCurrent()
assertThat(activeModes?.modeNames).containsExactly("Mode Bedtime")
assertThat(activeModes?.mainMode?.name).isEqualTo("Mode Bedtime")
zenModeRepository.deactivateMode("Bedtime")
- runCurrent()
assertThat(activeModes?.modeNames).hasSize(0)
assertThat(activeModes?.mainMode).isNull()
}
@Test
- fun getActiveModes_computesMainActiveMode() = runTest {
- zenModeRepository.addMode(id = "Bedtime", type = AutomaticZenRule.TYPE_BEDTIME)
- zenModeRepository.addMode(id = "Other", type = AutomaticZenRule.TYPE_OTHER)
-
- var activeModes = underTest.getActiveModes()
- assertThat(activeModes.modeNames).hasSize(0)
- assertThat(activeModes.mainMode).isNull()
-
- zenModeRepository.activateMode("Other")
- activeModes = underTest.getActiveModes()
- assertThat(activeModes.modeNames).containsExactly("Mode Other")
- assertThat(activeModes.mainMode?.name).isEqualTo("Mode Other")
-
- zenModeRepository.activateMode("Bedtime")
- activeModes = underTest.getActiveModes()
- assertThat(activeModes.modeNames).containsExactly("Mode Bedtime", "Mode Other").inOrder()
- assertThat(activeModes.mainMode?.name).isEqualTo("Mode Bedtime")
-
- zenModeRepository.deactivateMode("Other")
- activeModes = underTest.getActiveModes()
- assertThat(activeModes.modeNames).containsExactly("Mode Bedtime")
- assertThat(activeModes.mainMode?.name).isEqualTo("Mode Bedtime")
-
- zenModeRepository.deactivateMode("Bedtime")
- activeModes = underTest.getActiveModes()
- assertThat(activeModes.modeNames).hasSize(0)
- assertThat(activeModes.mainMode).isNull()
- }
+ fun getActiveModes_computesMainActiveMode() =
+ kosmos.runTest {
+ zenModeRepository.addMode(id = "Bedtime", type = AutomaticZenRule.TYPE_BEDTIME)
+ zenModeRepository.addMode(id = "Other", type = AutomaticZenRule.TYPE_OTHER)
+
+ var activeModes = underTest.getActiveModes()
+ assertThat(activeModes.modeNames).hasSize(0)
+ assertThat(activeModes.mainMode).isNull()
+
+ zenModeRepository.activateMode("Other")
+ activeModes = underTest.getActiveModes()
+ assertThat(activeModes.modeNames).containsExactly("Mode Other")
+ assertThat(activeModes.mainMode?.name).isEqualTo("Mode Other")
+
+ zenModeRepository.activateMode("Bedtime")
+ activeModes = underTest.getActiveModes()
+ assertThat(activeModes.modeNames)
+ .containsExactly("Mode Bedtime", "Mode Other")
+ .inOrder()
+ assertThat(activeModes.mainMode?.name).isEqualTo("Mode Bedtime")
+
+ zenModeRepository.deactivateMode("Other")
+ activeModes = underTest.getActiveModes()
+ assertThat(activeModes.modeNames).containsExactly("Mode Bedtime")
+ assertThat(activeModes.mainMode?.name).isEqualTo("Mode Bedtime")
+
+ zenModeRepository.deactivateMode("Bedtime")
+ activeModes = underTest.getActiveModes()
+ assertThat(activeModes.modeNames).hasSize(0)
+ assertThat(activeModes.mainMode).isNull()
+ }
@Test
fun mainActiveMode_flows() =
- testScope.runTest {
+ kosmos.runTest {
val mainActiveMode by collectLastValue(underTest.mainActiveMode)
zenModeRepository.addModes(
@@ -355,51 +316,42 @@ class ZenModeInteractorTest : SysuiTestCase() {
.build(),
)
)
-
- runCurrent()
assertThat(mainActiveMode).isNull()
zenModeRepository.activateMode("Other")
- runCurrent()
assertThat(mainActiveMode?.name).isEqualTo("Mode Other")
assertThat(mainActiveMode?.icon?.key?.resId)
.isEqualTo(R.drawable.ic_zen_mode_type_other)
zenModeRepository.activateMode("Bedtime")
- runCurrent()
assertThat(mainActiveMode?.name).isEqualTo("Mode Bedtime")
assertThat(mainActiveMode?.icon?.key?.resId)
.isEqualTo(R.drawable.ic_zen_mode_type_bedtime)
zenModeRepository.deactivateMode("Other")
- runCurrent()
assertThat(mainActiveMode?.name).isEqualTo("Mode Bedtime")
assertThat(mainActiveMode?.icon?.key?.resId)
.isEqualTo(R.drawable.ic_zen_mode_type_bedtime)
zenModeRepository.deactivateMode("Bedtime")
- runCurrent()
assertThat(mainActiveMode).isNull()
}
@Test
@EnableFlags(Flags.FLAG_MODES_UI)
fun dndMode_flows() =
- testScope.runTest {
+ kosmos.runTest {
val dndMode by collectLastValue(underTest.dndMode)
-
assertThat(dndMode!!.isActive).isFalse()
zenModeRepository.activateMode(MANUAL_DND)
- runCurrent()
-
assertThat(dndMode!!.isActive).isTrue()
}
@Test
@EnableFlags(Flags.FLAG_MODES_UI)
fun activeModesBlockingMedia_hasModesWithPolicyBlockingMedia() =
- testScope.runTest {
+ kosmos.runTest {
val blockingMedia by
collectLastValue(
underTest.activeModesBlockingStream(AudioStream(AudioManager.STREAM_MUSIC))
@@ -429,7 +381,6 @@ class ZenModeInteractorTest : SysuiTestCase() {
.build(),
)
)
- runCurrent()
assertThat(blockingMedia!!.mainMode!!.name).isEqualTo("Blocks media, Active")
assertThat(blockingMedia!!.modeNames)
@@ -440,7 +391,7 @@ class ZenModeInteractorTest : SysuiTestCase() {
@Test
@EnableFlags(Flags.FLAG_MODES_UI)
fun activeModesBlockingAlarms_hasModesWithPolicyBlockingAlarms() =
- testScope.runTest {
+ kosmos.runTest {
val blockingAlarms by
collectLastValue(
underTest.activeModesBlockingStream(AudioStream(AudioManager.STREAM_ALARM))
@@ -470,7 +421,6 @@ class ZenModeInteractorTest : SysuiTestCase() {
.build(),
)
)
- runCurrent()
assertThat(blockingAlarms!!.mainMode!!.name).isEqualTo("Blocks alarms, Active")
assertThat(blockingAlarms!!.modeNames)
@@ -481,7 +431,7 @@ class ZenModeInteractorTest : SysuiTestCase() {
@Test
@EnableFlags(Flags.FLAG_MODES_UI)
fun activeModesBlockingAlarms_hasModesWithPolicyBlockingSystem() =
- testScope.runTest {
+ kosmos.runTest {
val blockingSystem by
collectLastValue(
underTest.activeModesBlockingStream(AudioStream(AudioManager.STREAM_SYSTEM))
@@ -511,7 +461,6 @@ class ZenModeInteractorTest : SysuiTestCase() {
.build(),
)
)
- runCurrent()
assertThat(blockingSystem!!.mainMode!!.name).isEqualTo("Blocks system, Active")
assertThat(blockingSystem!!.modeNames)
@@ -522,7 +471,7 @@ class ZenModeInteractorTest : SysuiTestCase() {
@Test
@EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI, Flags.FLAG_MODES_API)
fun modesHidingNotifications_onlyIncludesModesWithNotifListSuppression() =
- testScope.runTest {
+ kosmos.runTest {
val modesHidingNotifications by collectLastValue(underTest.modesHidingNotifications)
zenModeRepository.addModes(
@@ -554,7 +503,6 @@ class ZenModeInteractorTest : SysuiTestCase() {
.build(),
)
)
- runCurrent()
assertThat(modesHidingNotifications?.map { it.name })
.containsExactly("Has list suppression 1", "Has list suppression 2")
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
index 0598b87aec9d..73e5004d47f0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.ui.viewmodel
+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
@@ -32,6 +34,7 @@ import com.android.systemui.scene.data.repository.sceneContainerRepository
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.headsup.shared.StatusBarNoHunBehavior
import com.android.systemui.statusbar.notification.data.repository.FakeHeadsUpRowRepository
import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
@@ -127,7 +130,8 @@ class KeyguardStatusBarViewModelTest(flags: FlagsParameterization) : SysuiTestCa
@Test
@EnableSceneContainer
- fun isVisible_headsUpStatusBarShown_false() =
+ @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+ fun isVisible_headsUpShown_noHunBehaviorFlagOff_false() =
testScope.runTest {
val latest by collectLastValue(underTest.isVisible)
@@ -145,6 +149,26 @@ class KeyguardStatusBarViewModelTest(flags: FlagsParameterization) : SysuiTestCa
}
@Test
+ @EnableSceneContainer
+ @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+ fun isVisible_headsUpShown_noHunBehaviorFlagOn_true() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isVisible)
+
+ // WHEN HUN displayed on the bypass lock screen
+ headsUpRepository.setNotifications(FakeHeadsUpRowRepository("key 0", isPinned = true))
+ keyguardTransitionRepository.emitInitialStepsFromOff(
+ KeyguardState.LOCKSCREEN,
+ testSetup = true,
+ )
+ kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
+ faceAuthRepository.isBypassEnabled.value = true
+
+ // THEN KeyguardStatusBar is still visible because StatusBarNoHunBehavior is enabled
+ assertThat(latest).isTrue()
+ }
+
+ @Test
fun isVisible_sceneLockscreen_andNotDozing_andNotShowingHeadsUpStatusBar_true() =
testScope.runTest {
val latest by collectLastValue(underTest.isVisible)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialActionStateSaverTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialActionStateSaverTest.kt
new file mode 100644
index 000000000000..4cbe33d66045
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialActionStateSaverTest.kt
@@ -0,0 +1,77 @@
+/*
+ * 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.touchpad.tutorial.ui.composable
+
+import androidx.compose.runtime.saveable.SaverScope
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.Error
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.Finished
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.InProgress
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.InProgressAfterError
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.NotStarted
+import com.android.systemui.res.R
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class TutorialActionStateSaverTest : SysuiTestCase() {
+
+ private val saver = TutorialActionState.stateSaver()
+ private val saverScope: SaverScope =
+ object : SaverScope {
+ override fun canBeSaved(value: Any) = true
+ }
+
+ @Test
+ fun inProgressIsRestoredToNotStartedState() {
+ assertRestoredState(
+ savedState = InProgress(progress = 0f),
+ expectedRestoredState = NotStarted,
+ )
+ }
+
+ @Test
+ fun inProgressErrorIsRestoredToErrorState() {
+ assertRestoredState(
+ savedState = InProgressAfterError(InProgress(progress = 0f)),
+ expectedRestoredState = Error,
+ )
+ }
+
+ @Test
+ fun otherStatesAreRestoredToTheSameState() {
+ assertRestoredState(savedState = NotStarted, expectedRestoredState = NotStarted)
+ assertRestoredState(savedState = Error, expectedRestoredState = Error)
+ assertRestoredState(
+ savedState = Finished(successAnimation = R.raw.trackpad_home_success),
+ expectedRestoredState = Finished(successAnimation = R.raw.trackpad_home_success),
+ )
+ }
+
+ private fun assertRestoredState(
+ savedState: TutorialActionState,
+ expectedRestoredState: TutorialActionState,
+ ) {
+ val savedValue = with(saver) { saverScope.save(savedState) }
+ assertThat(saver.restore(savedValue!!)).isEqualTo(expectedRestoredState)
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelTest.kt
index d8184dbadf9a..2dcfdd958df1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelTest.kt
@@ -30,6 +30,7 @@ import com.android.systemui.haptics.fakeVibratorHelper
import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.fakeVolumeDialogController
import com.android.systemui.testKosmos
+import com.android.systemui.util.time.fakeSystemClock
import com.android.systemui.volume.data.repository.audioSystemRepository
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -78,7 +79,7 @@ class VolumeDialogRingerDrawerViewModelTest : SysuiTestCase() {
val normalRingerMode = RingerMode(RINGER_MODE_NORMAL)
setUpRingerModeAndOpenDrawer(normalRingerMode)
- underTest.onRingerButtonClicked(normalRingerMode)
+ onRingerButtonClicked(normalRingerMode)
controller.getState()
assertThat(ringerViewModel).isInstanceOf(RingerViewModelState.Available::class.java)
@@ -95,7 +96,7 @@ class VolumeDialogRingerDrawerViewModelTest : SysuiTestCase() {
setUpRingerModeAndOpenDrawer(normalRingerMode)
// Select vibrate ringer mode.
- underTest.onRingerButtonClicked(vibrateRingerMode)
+ onRingerButtonClicked(vibrateRingerMode)
controller.getState()
runCurrent()
@@ -109,11 +110,11 @@ class VolumeDialogRingerDrawerViewModelTest : SysuiTestCase() {
val silentRingerMode = RingerMode(RINGER_MODE_SILENT)
// Open drawer
- underTest.onRingerButtonClicked(vibrateRingerMode)
+ onRingerButtonClicked(vibrateRingerMode)
controller.getState()
// Select silent ringer mode.
- underTest.onRingerButtonClicked(silentRingerMode)
+ onRingerButtonClicked(silentRingerMode)
controller.getState()
runCurrent()
@@ -152,11 +153,16 @@ class VolumeDialogRingerDrawerViewModelTest : SysuiTestCase() {
private fun TestScope.setUpRingerModeAndOpenDrawer(selectedRingerMode: RingerMode) {
setUpRingerMode(selectedRingerMode)
- underTest.onRingerButtonClicked(RingerMode(selectedRingerMode.value))
+ onRingerButtonClicked(selectedRingerMode)
controller.getState()
runCurrent()
}
+ private fun TestScope.onRingerButtonClicked(ringerMode: RingerMode) {
+ kosmos.fakeSystemClock.advanceTime(400L)
+ underTest.onRingerButtonClicked(ringerMode)
+ }
+
private fun TestScope.setUpRingerMode(selectedRingerMode: RingerMode) {
controller.setStreamVolume(STREAM_RING, 50)
controller.setRingerMode(selectedRingerMode.value, false)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioSharingInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioSharingInteractorTest.kt
index c9d147b6c81c..09d6ac6589ed 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioSharingInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioSharingInteractorTest.kt
@@ -16,11 +16,16 @@
package com.android.systemui.volume.domain.interactor
+import android.bluetooth.BluetoothDevice
import android.media.AudioManager.STREAM_MUSIC
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant
import com.android.settingslib.volume.shared.model.AudioStream
import com.android.systemui.SysuiTestCase
+import com.android.systemui.bluetooth.cachedBluetoothDeviceManager
+import com.android.systemui.bluetooth.localBluetoothProfileManager
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
@@ -32,6 +37,8 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
@@ -39,10 +46,23 @@ import org.junit.runner.RunWith
class AudioSharingInteractorTest : SysuiTestCase() {
private val kosmos = testKosmos()
lateinit var underTest: AudioSharingInteractor
+ private val bluetoothDevice: BluetoothDevice = mock {}
+ private val cachedDevice: CachedBluetoothDevice = mock {
+ on { groupId }.thenReturn(TEST_GROUP_ID)
+ on { device }.thenReturn(bluetoothDevice)
+ }
@Before
fun setUp() {
with(kosmos) {
+ whenever(cachedBluetoothDeviceManager.findDevice(bluetoothDevice))
+ .thenReturn(cachedDevice)
+ val broadcastAssistantProfile: LocalBluetoothLeBroadcastAssistant = mock {
+ on { allConnectedDevices }.thenReturn(listOf(bluetoothDevice))
+ }
+ whenever(localBluetoothProfileManager.leAudioBroadcastAssistantProfile)
+ .thenReturn(broadcastAssistantProfile)
+
with(audioSharingRepository) { setVolumeMap(mapOf(TEST_GROUP_ID to TEST_VOLUME)) }
underTest = audioSharingInteractor
}
@@ -90,6 +110,35 @@ class AudioSharingInteractorTest : SysuiTestCase() {
}
@Test
+ fun getPrimaryDevice() {
+ with(kosmos) {
+ testScope.runTest {
+ with(audioSharingRepository) { setPrimaryDevice(cachedDevice) }
+ underTest.handlePrimaryGroupChange()
+
+ val primaryDevice by collectLastValue(underTest.primaryDevice)
+ runCurrent()
+
+ Truth.assertThat(primaryDevice).isEqualTo(cachedDevice)
+ }
+ }
+ }
+
+ @Test
+ fun getSecondaryDevice() {
+ with(kosmos) {
+ testScope.runTest {
+ with(audioSharingRepository) { setSecondaryDevice(cachedDevice) }
+
+ val secondaryDevice by collectLastValue(underTest.secondaryDevice)
+ runCurrent()
+
+ Truth.assertThat(secondaryDevice).isEqualTo(cachedDevice)
+ }
+ }
+ }
+
+ @Test
fun handlePrimaryGroupChange_setStreamVolume() {
with(kosmos) {
testScope.runTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelTest.kt
new file mode 100644
index 000000000000..b34d7b8ec17d
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelTest.kt
@@ -0,0 +1,91 @@
+/*
+ * 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.volume.panel.component.volume.slider.ui.viewmodel
+
+import android.bluetooth.BluetoothDevice
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.uiEventLogger
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.haptics.slider.sliderHapticsViewModelFactory
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.testKosmos
+import com.android.systemui.volume.data.repository.audioSharingRepository
+import com.android.systemui.volume.domain.interactor.audioSharingInteractor
+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.mock
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AudioSharingStreamSliderViewModelTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+
+ private lateinit var stream: AudioSharingStreamSliderViewModel
+
+ @Before
+ fun setUp() {
+ stream = audioSharingStreamSliderViewModel()
+ }
+
+ private fun audioSharingStreamSliderViewModel(): AudioSharingStreamSliderViewModel {
+ return AudioSharingStreamSliderViewModel(
+ testScope.backgroundScope,
+ context,
+ kosmos.audioSharingInteractor,
+ kosmos.uiEventLogger,
+ kosmos.sliderHapticsViewModelFactory,
+ )
+ }
+
+ @Test
+ fun slider_media_inAudioSharing() =
+ with(kosmos) {
+ testScope.runTest {
+ val audioSharingSlider by collectLastValue(stream.slider)
+
+ val bluetoothDevice: BluetoothDevice = mock {}
+ val cachedDevice: CachedBluetoothDevice = mock {
+ on { groupId }.thenReturn(123)
+ on { device }.thenReturn(bluetoothDevice)
+ on { name }.thenReturn("my headset 2")
+ }
+ audioSharingRepository.setSecondaryDevice(cachedDevice)
+
+ audioSharingRepository.setInAudioSharing(true)
+ audioSharingRepository.setSecondaryGroupId(123)
+
+ runCurrent()
+
+ assertThat(audioSharingSlider!!.label).isEqualTo("my headset 2")
+ assertThat(audioSharingSlider!!.icon)
+ .isEqualTo(Icon.Resource(R.drawable.ic_volume_media_bt, null))
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelTest.kt
index 51cac6976362..9e8cde3bc936 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelTest.kt
@@ -23,19 +23,27 @@ import android.platform.test.annotations.EnableFlags
import android.service.notification.ZenPolicy
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.notification.modes.TestModeBuilder
import com.android.settingslib.volume.shared.model.AudioStream
import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runCurrent
import com.android.systemui.kosmos.runTest
+import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.data.repository.fakeZenModeRepository
import com.android.systemui.testKosmos
+import com.android.systemui.volume.data.repository.audioSharingRepository
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -146,4 +154,25 @@ class AudioStreamSliderViewModelTest : SysuiTestCase() {
assertThat(notificationSlider!!.disabledMessage)
.isEqualTo("Unavailable because ring is muted")
}
+
+ @Test
+ @EnableFlags(com.android.systemui.Flags.FLAG_SHOW_AUDIO_SHARING_SLIDER_IN_VOLUME_PANEL)
+ fun slider_media_inAudioSharing() =
+ kosmos.runTest {
+ val mediaSlider by
+ collectLastValue(audioStreamSliderViewModel(AudioManager.STREAM_MUSIC).slider)
+
+ val cachedDevice: CachedBluetoothDevice = mock {
+ on { groupId }.thenReturn(123)
+ on { name }.thenReturn("my headset 1")
+ }
+
+ audioSharingRepository.setInAudioSharing(true)
+ audioSharingRepository.setPrimaryDevice(cachedDevice)
+ runCurrent()
+
+ assertThat(mediaSlider!!.label).isEqualTo("my headset 1")
+ assertThat(mediaSlider!!.icon)
+ .isEqualTo(Icon.Resource(R.drawable.ic_volume_media_bt, null))
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/GradientColorWallpaperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/GradientColorWallpaperTest.kt
new file mode 100644
index 000000000000..ba6ea9f5e8bb
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/GradientColorWallpaperTest.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wallpapers
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.Rect
+import android.graphics.RectF
+import android.service.wallpaper.WallpaperService.Engine
+import android.testing.TestableLooper.RunWithLooper
+import android.view.Surface
+import android.view.SurfaceHolder
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+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.spy
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@RunWithLooper
+class GradientColorWallpaperTest : SysuiTestCase() {
+
+ @Mock private lateinit var surfaceHolder: SurfaceHolder
+
+ @Mock private lateinit var surface: Surface
+
+ @Mock private lateinit var canvas: Canvas
+
+ @Mock private lateinit var mockContext: Context
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ whenever(surfaceHolder.surface).thenReturn(surface)
+ whenever(surfaceHolder.surfaceFrame).thenReturn(surfaceFrame)
+ whenever(surface.lockHardwareCanvas()).thenReturn(canvas)
+ whenever(mockContext.getColor(anyInt())).thenReturn(1)
+ }
+
+ private fun createGradientColorWallpaperEngine(): Engine {
+ val gradientColorWallpaper = GradientColorWallpaper()
+ val engine = spy(gradientColorWallpaper.onCreateEngine())
+ whenever(engine.displayContext).thenReturn(mockContext)
+ return engine
+ }
+
+ @Test
+ fun onSurfaceRedrawNeeded_shouldDrawInCanvas() {
+ val engine = createGradientColorWallpaperEngine()
+ engine.onCreate(surfaceHolder)
+
+ engine.onSurfaceRedrawNeeded(surfaceHolder)
+
+ verify(canvas).drawRect(any<RectF>(), any<Paint>())
+ }
+
+ private companion object {
+ val surfaceFrame = Rect(0, 0, 100, 100)
+ }
+}
diff --git a/packages/SystemUI/res-product/values-iw/strings.xml b/packages/SystemUI/res-product/values-iw/strings.xml
index 0b289b7a44c0..8d78e6bd7cd0 100644
--- a/packages/SystemUI/res-product/values-iw/strings.xml
+++ b/packages/SystemUI/res-product/values-iw/strings.xml
@@ -21,7 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="dock_alignment_slow_charging" product="default" msgid="6997633396534416792">"צריך ליישר את הטלפון כדי לטעון אותו במהירות"</string>
<string name="dock_alignment_not_charging" product="default" msgid="3980752926226749808">"צריך ליישר את הטלפון כדי לטעון אותו באופן אלחוטי"</string>
- <string name="inattentive_sleep_warning_message" product="tv" msgid="6844464574089665063">"‏מכשיר ה-Android TV ייכבה בקרוב. יש ללחוץ על לחצן כלשהו כדי שהוא ימשיך לפעול."</string>
+ <string name="inattentive_sleep_warning_message" product="tv" msgid="6844464574089665063">"‏מכשיר ה-Android TV ייכבה בקרוב. יש ללחוץ על כפתור כלשהו כדי שהוא ימשיך לפעול."</string>
<string name="inattentive_sleep_warning_message" product="default" msgid="5693904520452332224">"המכשיר ייכבה בקרוב, יש ללחוץ כדי שהוא ימשיך לפעול."</string>
<string name="keyguard_missing_sim_message" product="tablet" msgid="408124574073032188">"‏אין כרטיס SIM בטאבלט."</string>
<string name="keyguard_missing_sim_message" product="default" msgid="2605468359948247208">"‏אין כרטיס SIM בטלפון."</string>
@@ -43,24 +43,24 @@
<string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"הטלפון כבה בגלל התחממות"</string>
<string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"המכשיר כבה בגלל התחממות"</string>
<string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"הטאבלט כבה בגלל התחממות"</string>
- <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"הטלפון פועל כרגיל עכשיו.\nיש להקיש כדי להציג מידע נוסף"</string>
- <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"המכשיר פועל כרגיל עכשיו.\nיש להקיש כדי להציג מידע נוסף"</string>
- <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"הטאבלט פועל כרגיל עכשיו.\nיש להקיש כדי להציג מידע נוסף"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"הטלפון פועל כרגיל עכשיו.\nיש ללחוץ כדי להציג מידע נוסף"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"המכשיר פועל כרגיל עכשיו.\nיש ללחוץ כדי להציג מידע נוסף"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"הטאבלט פועל כרגיל עכשיו.\nיש ללחוץ כדי להציג מידע נוסף"</string>
<string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"הטלפון שלך התחמם יותר מדי וכבה כדי להתקרר. הטלפון פועל כרגיל עכשיו.\n\nייתכן שהטלפון יתחמם יותר מדי אם:\n • משתמשים באפליקציות עתירות משאבים (כמו משחקים, אפליקציות וידאו או אפליקציות ניווט).\n • מורידים או מעלים קבצים גדולים.\n • משתמשים בטלפון בסביבה עם טמפרטורות גבוהות."</string>
<string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"המכשיר שלך התחמם יותר מדי וכבה כדי להתקרר. המכשיר פועל כרגיל עכשיו.\n\nייתכן שהמכשיר יתחמם יותר מדי אם:\n • משתמשים באפליקציות עתירות משאבים (כמו משחקים, אפליקציות וידאו או אפליקציות ניווט).\n • מורידים או מעלים קבצים גדולים.\n • משתמשים במכשיר בסביבה עם טמפרטורות גבוהות."</string>
<string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"הטאבלט שלך התחמם יותר מדי וכבה כדי להתקרר. הטאבלט פועל כרגיל עכשיו.\n\nייתכן שהטאבלט יתחמם יותר מדי אם:\n • משתמשים באפליקציות עתירות משאבים (כמו משחקים, אפליקציות וידאו או אפליקציות ניווט).\n • מורידים או מעלים קבצים גדולים.\n • משתמשים בטאבלט בסביבה עם טמפרטורות גבוהות."</string>
<string name="high_temp_title" product="default" msgid="5365000411304924115">"הטלפון מתחמם"</string>
<string name="high_temp_title" product="device" msgid="6622009907401563664">"המכשיר מתחמם"</string>
<string name="high_temp_title" product="tablet" msgid="9039733706606446616">"הטאבלט מתחמם"</string>
- <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"חלק מהתכונות מוגבלות כל עוד הטלפון מתקרר.\nיש להקיש כדי להציג מידע נוסף"</string>
- <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"חלק מהתכונות מוגבלות כל עוד המכשיר מתקרר.\nיש להקיש כדי להציג מידע נוסף"</string>
- <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"חלק מהתכונות מוגבלות כל עוד הטאבלט מתקרר.\nיש להקיש כדי להציג מידע נוסף"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"חלק מהתכונות מוגבלות כל עוד הטלפון מתקרר.\nיש ללחוץ כדי להציג מידע נוסף"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"חלק מהתכונות מוגבלות כל עוד המכשיר מתקרר.\nיש ללחוץ כדי להציג מידע נוסף"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"חלק מהתכונות מוגבלות כל עוד הטאבלט מתקרר.\nיש ללחוץ כדי להציג מידע נוסף"</string>
<string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"קירור הטלפון ייעשה באופן אוטומטי. אפשר עדיין להשתמש בטלפון, אבל ייתכן שהוא יפעל לאט יותר.\n\nהטלפון יחזור לפעול כרגיל לאחר שיתקרר."</string>
<string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"קירור המכשיר ייעשה באופן אוטומטי. אפשר עדיין להשתמש במכשיר אבל ייתכן שהוא יפעל לאט יותר.\n\nהמכשיר יחזור לפעול כרגיל לאחר שיתקרר."</string>
<string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"קירור הטאבלט ייעשה באופן אוטומטי. אפשר עדיין להשתמש בטאבלט אבל ייתכן שהוא יפעל לאט יותר.\n\nהטאבלט יחזור לפעול כרגיל לאחר שיתקרר."</string>
- <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"חיישן טביעות האצבע נמצא על לחצן ההפעלה. זה הלחצן השטוח ליד הלחצן הבולט של עוצמת הקול בקצה הטאבלט."</string>
- <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"חיישן טביעות האצבע נמצא על לחצן ההפעלה. זה הלחצן השטוח ליד הלחצן הבולט של עוצמת הקול בשולי המכשיר."</string>
- <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"חיישן טביעות האצבע נמצא על לחצן ההפעלה. זה הלחצן השטוח ליד הלחצן הבולט של עוצמת הקול בקצה הטלפון."</string>
+ <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"חיישן טביעות האצבע נמצא על כפתור ההפעלה. זה הכפתור השטוח ליד הכפתור הבולט של עוצמת הקול בקצה הטאבלט."</string>
+ <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"חיישן טביעות האצבע נמצא על כפתור ההפעלה. זה הכפתור השטוח ליד הכפתור הבולט של עוצמת הקול בשולי המכשיר."</string>
+ <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"חיישן טביעות האצבע נמצא על כפתור ההפעלה. זה הכפתור השטוח ליד הכפתור הבולט של עוצמת הקול בקצה הטלפון."</string>
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"לאפשרויות נוספות, יש לבטל את נעילת הטלפון"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"לאפשרויות נוספות, יש לבטל את נעילת הטאבלט"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"לאפשרויות נוספות, יש לבטל את נעילת המכשיר"</string>
diff --git a/packages/SystemUI/res/drawable/android16_patch_adaptive.xml b/packages/SystemUI/res/drawable/android16_patch_adaptive.xml
new file mode 100644
index 000000000000..277df47438e3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/android16_patch_adaptive.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.
+-->
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/android16_patch_adaptive_background"/>
+ <foreground android:drawable="@drawable/android16_patch_adaptive_foreground"/>
+ <monochrome android:drawable="@drawable/android16_patch_monochrome"/>
+</adaptive-icon>
diff --git a/packages/SystemUI/res/drawable/android16_patch_adaptive_background.xml b/packages/SystemUI/res/drawable/android16_patch_adaptive_background.xml
new file mode 100644
index 000000000000..17c2b927f4fd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/android16_patch_adaptive_background.xml
@@ -0,0 +1,245 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <group>
+ <clip-path
+ android:pathData="M0,0h108v108h-108z"/>
+ <path
+ android:pathData="M73,54L54,35L35,54L54,73L73,54Z"
+ android:fillColor="#34A853"/>
+ <path
+ android:pathData="M44.5,44.5L54,44.5L44.5,54L44.5,44.5Z"
+ android:fillColor="#1F8E3D"/>
+ <path
+ android:pathData="M63.5,63.5L54,63.5L63.5,54L63.5,63.5Z"
+ android:fillColor="#1F8E3D"/>
+ <path
+ android:pathData="M54,54L54,44.5L63.5,54L54,54Z"
+ android:fillColor="#1F8E3D"/>
+ <path
+ android:pathData="M54,44.5L54,35L63.5,44.5L54,44.5Z"
+ android:fillColor="#1F8E3D"/>
+ <path
+ android:pathData="M54,63.5L54,73L44.5,63.5L54,63.5Z"
+ android:fillColor="#1F8E3D"/>
+ <path
+ android:pathData="M63.5,54L63.5,44.5L73,54L63.5,54Z"
+ android:fillColor="#1F8E3D"/>
+ <path
+ android:pathData="M44.5,54L44.5,63.5L35,54L44.5,54Z"
+ android:fillColor="#1F8E3D"/>
+ <path
+ android:pathData="M54,54L54,63.5L44.5,54L54,54Z"
+ android:fillColor="#1F8E3D"/>
+ <path
+ android:pathData="M82.5,25.5L82.5,35L73,25.5L82.5,25.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M63.5,44.5L63.5,35L73,44.5L63.5,44.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M73,35L82.5,35L73,44.5L73,35Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M82.5,35L92,35L82.5,44.5L82.5,35Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M63.5,35L54,35L63.5,25.5L63.5,35Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M73,44.5L82.5,44.5L73,54L73,44.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M73,25.5L63.5,25.5L73,16L73,25.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M73,35L63.5,35L73,25.5L73,35Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M82.5,63.5L82.5,73L73,63.5L82.5,63.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M63.5,82.5L63.5,73L73,82.5L63.5,82.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M73,73L82.5,73L73,82.5L73,73Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M82.5,73L92,73L82.5,82.5L82.5,73Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M63.5,73L54,73L63.5,63.5L63.5,73Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M73,82.5L82.5,82.5L73,92L73,82.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M73,63.5L63.5,63.5L73,54L73,63.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M73,73L63.5,73L73,63.5L73,73Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M44.5,63.5L44.5,73L35,63.5L44.5,63.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M25.5,82.5L25.5,73L35,82.5L25.5,82.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M35,73L44.5,73L35,82.5L35,73Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M44.5,73L54,73L44.5,82.5L44.5,73Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M25.5,73L16,73L25.5,63.5L25.5,73Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M35,82.5L44.5,82.5L35,92L35,82.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M35,63.5L25.5,63.5L35,54L35,63.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M35,73L25.5,73L35,63.5L35,73Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M44.5,25.5L44.5,35L35,25.5L44.5,25.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M25.5,44.5L25.5,35L35,44.5L25.5,44.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M35,35L44.5,35L35,44.5L35,35Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M44.5,35L54,35L44.5,44.5L44.5,35Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M25.5,35L16,35L25.5,25.5L25.5,35Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M35,44.5L44.5,44.5L35,54L35,44.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M35,25.5L25.5,25.5L35,16L35,25.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M35,35L25.5,35L35,25.5L35,35Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M63.5,25.5L54,25.5L63.5,16L63.5,25.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M44.5,6.5L54,6.5L44.5,16L44.5,6.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M54,16L54,25.5L44.5,16L54,16Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M54,25.5L54,35L44.5,25.5L54,25.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M54,6.5L54,-3L63.5,6.5L54,6.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M44.5,16L44.5,25.5L35,16L44.5,16Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M63.5,16L63.5,6.5L73,16L63.5,16Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M54,16L54,6.5L63.5,16L54,16Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M101.5,63.5L92,63.5L101.5,54L101.5,63.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M82.5,44.5L92,44.5L82.5,54L82.5,44.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M92,54L92,63.5L82.5,54L92,54Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M92,63.5L92,73L82.5,63.5L92,63.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M92,44.5L92,35L101.5,44.5L92,44.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M82.5,54L82.5,63.5L73,54L82.5,54Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M101.5,54L101.5,44.5L111,54L101.5,54Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M92,54L92,44.5L101.5,54L92,54Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M63.5,101.5L54,101.5L63.5,92L63.5,101.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M44.5,82.5L54,82.5L44.5,92L44.5,82.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M54,92L54,101.5L44.5,92L54,92Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M54,101.5L54,111L44.5,101.5L54,101.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M54,82.5L54,73L63.5,82.5L54,82.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M44.5,92L44.5,101.5L35,92L44.5,92Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M63.5,92L63.5,82.5L73,92L63.5,92Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M54,92L54,82.5L63.5,92L54,92Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M25.5,63.5L16,63.5L25.5,54L25.5,63.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M6.5,44.5L16,44.5L6.5,54L6.5,44.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M16,54L16,63.5L6.5,54L16,54Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M16,63.5L16,73L6.5,63.5L16,63.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M16,44.5L16,35L25.5,44.5L16,44.5Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M6.5,54L6.5,63.5L-3,54L6.5,54Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M25.5,54L25.5,44.5L35,54L25.5,54Z"
+ android:fillColor="#16161D"/>
+ <path
+ android:pathData="M16,54L16,44.5L25.5,54L16,54Z"
+ android:fillColor="#16161D"/>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/android16_patch_adaptive_foreground.xml b/packages/SystemUI/res/drawable/android16_patch_adaptive_foreground.xml
new file mode 100644
index 000000000000..4c2932399c1a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/android16_patch_adaptive_foreground.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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:pathData="M40.65,63.013C40.722,62.922 40.716,62.789 40.633,62.707V62.707C40.537,62.61 40.377,62.62 40.292,62.727C34.567,69.881 31.569,75.536 33.089,77.056C35.366,79.333 46.923,71.469 58.901,59.491C60.049,58.343 61.159,57.199 62.226,56.066C62.342,55.943 62.339,55.751 62.219,55.632L61.566,54.978C61.441,54.854 61.238,54.857 61.117,54.985C60.057,56.11 58.951,57.25 57.806,58.395C46.882,69.319 36.496,76.646 34.61,74.759C33.417,73.567 35.903,68.982 40.65,63.013Z"
+ android:fillColor="#C6FF00"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M67.956,52.033C68.205,51.966 68.462,52.115 68.529,52.364C68.596,52.614 68.448,52.871 68.198,52.938L67.956,52.033ZM68.198,52.938L63.926,54.083L63.683,53.178L67.956,52.033L68.198,52.938Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M64.497,49.237C64.564,48.987 64.821,48.839 65.071,48.906C65.32,48.973 65.469,49.229 65.402,49.479L64.497,49.237ZM65.402,49.479L64.257,53.752L63.352,53.509L64.497,49.237L65.402,49.479Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M66.145,51.236C64.869,49.961 62.83,49.931 61.591,51.17L58.825,53.937C58.585,54.176 58.585,54.564 58.825,54.803C59.063,55.042 59.452,55.042 59.691,54.803L60.436,54.057C60.915,53.579 61.69,53.579 62.169,54.057L63.324,55.212C63.802,55.691 63.802,56.466 63.324,56.945L62.578,57.69C62.339,57.929 62.339,58.318 62.578,58.557C62.817,58.796 63.205,58.796 63.444,58.557L66.211,55.79C67.45,54.551 67.42,52.512 66.145,51.236Z"
+ android:fillColor="#000000"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/android16_patch_monochrome.xml b/packages/SystemUI/res/drawable/android16_patch_monochrome.xml
new file mode 100644
index 000000000000..608d5ea6ee48
--- /dev/null
+++ b/packages/SystemUI/res/drawable/android16_patch_monochrome.xml
@@ -0,0 +1,113 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:strokeWidth="1"
+ android:pathData="M54.707,35.707L72.293,53.293A1,1 102.155,0 1,72.293 54.707L54.707,72.293A1,1 0,0 1,53.293 72.293L35.707,54.707A1,1 0,0 1,35.707 53.293L53.293,35.707A1,1 0,0 1,54.707 35.707z"
+ android:fillColor="#00000000"
+ android:strokeColor="#ffffff"/>
+ <path
+ android:pathData="M55.237,35.177L72.823,52.763A1.75,1.75 67.835,0 1,72.823 55.237L55.237,72.823A1.75,1.75 77.684,0 1,52.763 72.823L35.177,55.237A1.75,1.75 0,0 1,35.177 52.763L52.763,35.177A1.75,1.75 0,0 1,55.237 35.177z"
+ android:strokeWidth="1.5"
+ android:fillColor="#00000000"
+ android:strokeColor="#ffffff"/>
+ <path
+ android:pathData="M44.5,44.5h19v19h-19z"
+ android:strokeWidth="0.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#ffffff"/>
+ <path
+ android:pathData="M54,44.5l9.5,9.5l-9.5,9.5l-9.5,-9.5z"
+ android:strokeWidth="0.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#ffffff"/>
+ <path
+ android:pathData="M54,35V73"
+ android:strokeWidth="0.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#ffffff"/>
+ <path
+ android:pathData="M73,54L35,54"
+ android:strokeWidth="0.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#ffffff"/>
+ <path
+ android:pathData="M33.576,31.135l1.146,1.146l-1.146,1.146l-1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M31.146,65.966l1.146,1.146l-1.146,1.146l-1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M26.718,56l1.718,1.718l-1.718,1.718l-1.718,-1.718z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M31.146,48l1.146,1.146l-1.146,1.146l-1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M41.925,34.374l1.718,1.718l-1.718,1.718l-1.718,-1.718z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M63.146,71l1.146,1.146l-1.146,1.146l-1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M48.567,74.553l1.718,1.718l-1.718,1.718l-1.718,-1.718z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M51.146,26l1.146,1.146l-1.146,1.146l-1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M72.291,32.146l-1.146,1.146l-1.146,-1.146l1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M76.531,36.417l-1.718,1.718l-1.718,-1.718l1.718,-1.718z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M58.291,32.146l-1.146,1.146l-1.146,-1.146l1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M68.419,36.978l-1.146,1.146l-1.146,-1.146l1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M74.252,64.034l-1.146,1.146l-1.146,-1.146l1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M71.437,76.718l-1.718,1.718l-1.718,-1.718l1.718,-1.718z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M42.984,69.38l-1.146,1.146l-1.146,-1.146l1.146,-1.146z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M82.437,51.718l-1.718,1.718l-1.718,-1.718l1.718,-1.718z"
+ android:fillColor="#E8F5E9"/>
+ <path
+ android:pathData="M40.65,63.013C40.722,62.922 40.716,62.789 40.633,62.707V62.707C40.537,62.61 40.377,62.62 40.292,62.727C34.567,69.881 31.569,75.536 33.089,77.056C35.366,79.333 46.923,71.469 58.901,59.491C60.049,58.343 61.159,57.199 62.226,56.066C62.342,55.943 62.339,55.751 62.219,55.632L61.566,54.978C61.441,54.854 61.238,54.857 61.117,54.985C60.057,56.11 58.951,57.25 57.806,58.395C46.882,69.319 36.496,76.646 34.61,74.759C33.417,73.567 35.903,68.982 40.65,63.013Z"
+ android:fillColor="#ffffff"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M67.956,52.033C68.205,51.966 68.462,52.115 68.529,52.364C68.596,52.614 68.448,52.871 68.198,52.938L67.956,52.033ZM68.198,52.938L63.926,54.083L63.683,53.178L67.956,52.033L68.198,52.938Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M64.497,49.237C64.564,48.987 64.821,48.839 65.071,48.906C65.32,48.972 65.469,49.229 65.402,49.479L64.497,49.237ZM65.402,49.479L64.257,53.752L63.352,53.509L64.497,49.237L65.402,49.479Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M66.145,51.236C64.869,49.961 62.83,49.931 61.591,51.17L58.825,53.937C58.585,54.176 58.585,54.564 58.825,54.803C59.063,55.042 59.452,55.042 59.691,54.803L60.436,54.057C60.915,53.579 61.69,53.579 62.169,54.057L63.324,55.212C63.802,55.691 63.802,56.466 63.324,56.945L62.578,57.69C62.339,57.929 62.339,58.318 62.578,58.556C62.817,58.796 63.205,58.796 63.444,58.556L66.211,55.79C67.45,54.551 67.42,52.512 66.145,51.236Z"
+ android:fillColor="#ffffff"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_media_connecting_button_container.xml b/packages/SystemUI/res/drawable/ic_media_connecting_button_container.xml
new file mode 100644
index 000000000000..32aacf6522e7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_media_connecting_button_container.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2025 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="88dp"
+ android:height="56dp"
+ android:viewportHeight="56"
+ android:viewportWidth="88">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_1_G"
+ android:scaleX="1.05905"
+ android:scaleY="1.0972"
+ android:translateX="43.528999999999996"
+ android:translateY="27.898" />
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="0.493"
+ android:pivotY="0.124"
+ android:scaleX="1.05905"
+ android:scaleY="1.0972"
+ android:translateX="43.528999999999996"
+ android:translateY="27.898">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#3d90ff"
+ android:fillType="nonZero"
+ android:pathData=" M34.49 -5.75 C34.49,-5.75 34.49,6 34.49,6 C34.49,14.84 27.32,22 18.49,22 C18.49,22 -17.5,22 -17.5,22 C-26.34,22 -33.5,14.84 -33.5,6 C-33.5,6 -33.5,-5.75 -33.5,-5.75 C-33.5,-14.59 -26.34,-21.75 -17.5,-21.75 C-17.5,-21.75 18.49,-21.75 18.49,-21.75 C27.32,-21.75 34.49,-14.59 34.49,-5.75c " />
+ </group>
+ </group>
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_media_connecting_status_container.xml b/packages/SystemUI/res/drawable/ic_media_connecting_status_container.xml
deleted file mode 100644
index f8c0fa04cd39..000000000000
--- a/packages/SystemUI/res/drawable/ic_media_connecting_status_container.xml
+++ /dev/null
@@ -1,199 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2025 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:aapt="http://schemas.android.com/aapt">
- <target android:name="_R_G_L_1_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="83"
- android:propertyName="scaleX"
- android:startOffset="1000"
- android:valueFrom="0.45561"
- android:valueTo="0.69699"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="83"
- android:propertyName="scaleY"
- android:startOffset="1000"
- android:valueFrom="0.6288400000000001"
- android:valueTo="0.81618"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="417"
- android:propertyName="scaleX"
- android:startOffset="1083"
- android:valueFrom="0.69699"
- android:valueTo="1.05905"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="417"
- android:propertyName="scaleY"
- android:startOffset="1083"
- android:valueFrom="0.81618"
- android:valueTo="1.0972"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="500"
- android:propertyName="rotation"
- android:startOffset="0"
- android:valueFrom="90"
- android:valueTo="135"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="500"
- android:propertyName="rotation"
- android:startOffset="500"
- android:valueFrom="135"
- android:valueTo="180"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="83"
- android:propertyName="scaleX"
- android:startOffset="1000"
- android:valueFrom="0.0434"
- android:valueTo="0.05063"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="83"
- android:propertyName="scaleY"
- android:startOffset="1000"
- android:valueFrom="0.0434"
- android:valueTo="0.042350000000000006"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.8,0.15 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="417"
- android:propertyName="scaleX"
- android:startOffset="1083"
- android:valueFrom="0.05063"
- android:valueTo="0.06146"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="417"
- android:propertyName="scaleY"
- android:startOffset="1083"
- android:valueFrom="0.042350000000000006"
- android:valueTo="0.040780000000000004"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.05,0.7 0.1,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="time_group">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="1017"
- android:propertyName="translateX"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType" />
- </set>
- </aapt:attr>
- </target>
- <aapt:attr name="android:drawable">
- <vector
- android:width="88dp"
- android:height="56dp"
- android:viewportHeight="56"
- android:viewportWidth="88">
- <group android:name="_R_G">
- <group
- android:name="_R_G_L_1_G"
- android:pivotX="0.493"
- android:pivotY="0.124"
- android:scaleX="1.05905"
- android:scaleY="1.0972"
- android:translateX="43.528999999999996"
- android:translateY="27.898">
- <path
- android:name="_R_G_L_1_G_D_0_P_0"
- android:fillAlpha="1"
- android:fillColor="#3d90ff"
- android:fillType="nonZero"
- android:pathData=" M34.47 0.63 C34.47,0.63 34.42,0.64 34.42,0.64 C33.93,12.88 24.69,21.84 13.06,21.97 C13.06,21.97 -12.54,21.97 -12.54,21.97 C-23.11,21.84 -33.38,13.11 -33.52,-0.27 C-33.52,-0.27 -33.52,-0.05 -33.52,-0.05 C-33.5,-13.21 -21.73,-21.76 -12.9,-21.76 C-12.9,-21.76 14.59,-21.76 14.59,-21.76 C24.81,-21.88 34.49,-10.58 34.47,0.63c " />
- </group>
- <group
- android:name="_R_G_L_0_G"
- android:rotation="0"
- android:scaleX="0.06146"
- android:scaleY="0.040780000000000004"
- android:translateX="44"
- android:translateY="28">
- <path
- android:name="_R_G_L_0_G_D_0_P_0"
- android:fillAlpha="1"
- android:fillColor="#3d90ff"
- android:fillType="nonZero"
- android:pathData=" M-0.65 -437.37 C-0.65,-437.37 8.33,-437.66 8.33,-437.66 C8.33,-437.66 17.31,-437.95 17.31,-437.95 C17.31,-437.95 26.25,-438.78 26.25,-438.78 C26.25,-438.78 35.16,-439.95 35.16,-439.95 C35.16,-439.95 44.07,-441.11 44.07,-441.11 C44.07,-441.11 52.85,-443 52.85,-443 C52.85,-443 61.6,-445.03 61.6,-445.03 C61.6,-445.03 70.35,-447.09 70.35,-447.09 C70.35,-447.09 78.91,-449.83 78.91,-449.83 C78.91,-449.83 87.43,-452.67 87.43,-452.67 C87.43,-452.67 95.79,-455.97 95.79,-455.97 C95.79,-455.97 104.11,-459.35 104.11,-459.35 C104.11,-459.35 112.36,-462.93 112.36,-462.93 C112.36,-462.93 120.6,-466.51 120.6,-466.51 C120.6,-466.51 128.84,-470.09 128.84,-470.09 C128.84,-470.09 137.09,-473.67 137.09,-473.67 C137.09,-473.67 145.49,-476.84 145.49,-476.84 C145.49,-476.84 153.9,-480.01 153.9,-480.01 C153.9,-480.01 162.31,-483.18 162.31,-483.18 C162.31,-483.18 170.98,-485.54 170.98,-485.54 C170.98,-485.54 179.66,-487.85 179.66,-487.85 C179.66,-487.85 188.35,-490.15 188.35,-490.15 C188.35,-490.15 197.22,-491.58 197.22,-491.58 C197.22,-491.58 206.09,-493.01 206.09,-493.01 C206.09,-493.01 214.98,-494.28 214.98,-494.28 C214.98,-494.28 223.95,-494.81 223.95,-494.81 C223.95,-494.81 232.93,-495.33 232.93,-495.33 C232.93,-495.33 241.9,-495.5 241.9,-495.5 C241.9,-495.5 250.88,-495.13 250.88,-495.13 C250.88,-495.13 259.86,-494.75 259.86,-494.75 C259.86,-494.75 268.78,-493.78 268.78,-493.78 C268.78,-493.78 277.68,-492.52 277.68,-492.52 C277.68,-492.52 286.57,-491.26 286.57,-491.26 C286.57,-491.26 295.31,-489.16 295.31,-489.16 C295.31,-489.16 304.04,-487.04 304.04,-487.04 C304.04,-487.04 312.7,-484.65 312.7,-484.65 C312.7,-484.65 321.19,-481.72 321.19,-481.72 C321.19,-481.72 329.68,-478.78 329.68,-478.78 C329.68,-478.78 337.96,-475.31 337.96,-475.31 C337.96,-475.31 346.14,-471.59 346.14,-471.59 C346.14,-471.59 354.3,-467.82 354.3,-467.82 C354.3,-467.82 362.11,-463.38 362.11,-463.38 C362.11,-463.38 369.92,-458.93 369.92,-458.93 C369.92,-458.93 377.53,-454.17 377.53,-454.17 C377.53,-454.17 384.91,-449.04 384.91,-449.04 C384.91,-449.04 392.29,-443.91 392.29,-443.91 C392.29,-443.91 399.26,-438.24 399.26,-438.24 C399.26,-438.24 406.15,-432.48 406.15,-432.48 C406.15,-432.48 412.92,-426.57 412.92,-426.57 C412.92,-426.57 419.27,-420.22 419.27,-420.22 C419.27,-420.22 425.62,-413.87 425.62,-413.87 C425.62,-413.87 431.61,-407.18 431.61,-407.18 C431.61,-407.18 437.38,-400.29 437.38,-400.29 C437.38,-400.29 443.14,-393.39 443.14,-393.39 C443.14,-393.39 448.27,-386.01 448.27,-386.01 C448.27,-386.01 453.4,-378.64 453.4,-378.64 C453.4,-378.64 458.26,-371.09 458.26,-371.09 C458.26,-371.09 462.71,-363.28 462.71,-363.28 C462.71,-363.28 467.16,-355.47 467.16,-355.47 C467.16,-355.47 471.03,-347.37 471.03,-347.37 C471.03,-347.37 474.75,-339.19 474.75,-339.19 C474.75,-339.19 478.34,-330.95 478.34,-330.95 C478.34,-330.95 481.28,-322.46 481.28,-322.46 C481.28,-322.46 484.21,-313.97 484.21,-313.97 C484.21,-313.97 486.72,-305.35 486.72,-305.35 C486.72,-305.35 488.84,-296.62 488.84,-296.62 C488.84,-296.62 490.96,-287.88 490.96,-287.88 C490.96,-287.88 492.33,-279.01 492.33,-279.01 C492.33,-279.01 493.59,-270.11 493.59,-270.11 C493.59,-270.11 494.69,-261.2 494.69,-261.2 C494.69,-261.2 495.07,-252.22 495.07,-252.22 C495.07,-252.22 495.44,-243.24 495.44,-243.24 C495.44,-243.24 495.41,-234.27 495.41,-234.27 C495.41,-234.27 494.88,-225.29 494.88,-225.29 C494.88,-225.29 494.35,-216.32 494.35,-216.32 C494.35,-216.32 493.22,-207.42 493.22,-207.42 C493.22,-207.42 491.79,-198.55 491.79,-198.55 C491.79,-198.55 490.36,-189.68 490.36,-189.68 C490.36,-189.68 488.19,-180.96 488.19,-180.96 C488.19,-180.96 485.88,-172.28 485.88,-172.28 C485.88,-172.28 483.56,-163.6 483.56,-163.6 C483.56,-163.6 480.48,-155.16 480.48,-155.16 C480.48,-155.16 477.31,-146.75 477.31,-146.75 C477.31,-146.75 474.14,-138.34 474.14,-138.34 C474.14,-138.34 470.62,-130.07 470.62,-130.07 C470.62,-130.07 467.04,-121.83 467.04,-121.83 C467.04,-121.83 463.46,-113.59 463.46,-113.59 C463.46,-113.59 459.88,-105.35 459.88,-105.35 C459.88,-105.35 456.54,-97.01 456.54,-97.01 C456.54,-97.01 453.37,-88.6 453.37,-88.6 C453.37,-88.6 450.21,-80.19 450.21,-80.19 C450.21,-80.19 447.68,-71.57 447.68,-71.57 C447.68,-71.57 445.36,-62.89 445.36,-62.89 C445.36,-62.89 443.04,-54.21 443.04,-54.21 C443.04,-54.21 441.54,-45.35 441.54,-45.35 C441.54,-45.35 440.09,-36.48 440.09,-36.48 C440.09,-36.48 438.78,-27.6 438.78,-27.6 C438.78,-27.6 438.19,-18.63 438.19,-18.63 C438.19,-18.63 437.61,-9.66 437.61,-9.66 C437.61,-9.66 437.36,-0.69 437.36,-0.69 C437.36,-0.69 437.65,8.29 437.65,8.29 C437.65,8.29 437.95,17.27 437.95,17.27 C437.95,17.27 438.77,26.21 438.77,26.21 C438.77,26.21 439.94,35.12 439.94,35.12 C439.94,35.12 441.11,44.03 441.11,44.03 C441.11,44.03 442.99,52.81 442.99,52.81 C442.99,52.81 445.02,61.57 445.02,61.57 C445.02,61.57 447.07,70.31 447.07,70.31 C447.07,70.31 449.82,78.87 449.82,78.87 C449.82,78.87 452.65,87.4 452.65,87.4 C452.65,87.4 455.96,95.75 455.96,95.75 C455.96,95.75 459.33,104.08 459.33,104.08 C459.33,104.08 462.91,112.32 462.91,112.32 C462.91,112.32 466.49,120.57 466.49,120.57 C466.49,120.57 470.07,128.81 470.07,128.81 C470.07,128.81 473.65,137.05 473.65,137.05 C473.65,137.05 476.82,145.46 476.82,145.46 C476.82,145.46 479.99,153.87 479.99,153.87 C479.99,153.87 483.17,162.28 483.17,162.28 C483.17,162.28 485.52,170.94 485.52,170.94 C485.52,170.94 487.84,179.63 487.84,179.63 C487.84,179.63 490.14,188.31 490.14,188.31 C490.14,188.31 491.57,197.18 491.57,197.18 C491.57,197.18 493,206.06 493,206.06 C493,206.06 494.27,214.95 494.27,214.95 C494.27,214.95 494.8,223.92 494.8,223.92 C494.8,223.92 495.33,232.89 495.33,232.89 C495.33,232.89 495.5,241.86 495.5,241.86 C495.5,241.86 495.12,250.84 495.12,250.84 C495.12,250.84 494.75,259.82 494.75,259.82 C494.75,259.82 493.78,268.74 493.78,268.74 C493.78,268.74 492.52,277.64 492.52,277.64 C492.52,277.64 491.27,286.54 491.27,286.54 C491.27,286.54 489.16,295.27 489.16,295.27 C489.16,295.27 487.05,304.01 487.05,304.01 C487.05,304.01 484.66,312.66 484.66,312.66 C484.66,312.66 481.73,321.16 481.73,321.16 C481.73,321.16 478.79,329.65 478.79,329.65 C478.79,329.65 475.32,337.93 475.32,337.93 C475.32,337.93 471.6,346.11 471.6,346.11 C471.6,346.11 467.84,354.27 467.84,354.27 C467.84,354.27 463.39,362.08 463.39,362.08 C463.39,362.08 458.94,369.89 458.94,369.89 C458.94,369.89 454.19,377.5 454.19,377.5 C454.19,377.5 449.06,384.88 449.06,384.88 C449.06,384.88 443.93,392.26 443.93,392.26 C443.93,392.26 438.26,399.23 438.26,399.23 C438.26,399.23 432.5,406.12 432.5,406.12 C432.5,406.12 426.6,412.89 426.6,412.89 C426.6,412.89 420.24,419.24 420.24,419.24 C420.24,419.24 413.89,425.6 413.89,425.6 C413.89,425.6 407.2,431.59 407.2,431.59 C407.2,431.59 400.31,437.36 400.31,437.36 C400.31,437.36 393.42,443.12 393.42,443.12 C393.42,443.12 386.04,448.25 386.04,448.25 C386.04,448.25 378.66,453.38 378.66,453.38 C378.66,453.38 371.11,458.24 371.11,458.24 C371.11,458.24 363.31,462.69 363.31,462.69 C363.31,462.69 355.5,467.14 355.5,467.14 C355.5,467.14 347.4,471.02 347.4,471.02 C347.4,471.02 339.22,474.73 339.22,474.73 C339.22,474.73 330.99,478.33 330.99,478.33 C330.99,478.33 322.49,481.27 322.49,481.27 C322.49,481.27 314,484.2 314,484.2 C314,484.2 305.38,486.71 305.38,486.71 C305.38,486.71 296.65,488.83 296.65,488.83 C296.65,488.83 287.91,490.95 287.91,490.95 C287.91,490.95 279.04,492.33 279.04,492.33 C279.04,492.33 270.14,493.59 270.14,493.59 C270.14,493.59 261.23,494.69 261.23,494.69 C261.23,494.69 252.25,495.07 252.25,495.07 C252.25,495.07 243.28,495.44 243.28,495.44 C243.28,495.44 234.3,495.41 234.3,495.41 C234.3,495.41 225.33,494.88 225.33,494.88 C225.33,494.88 216.36,494.35 216.36,494.35 C216.36,494.35 207.45,493.23 207.45,493.23 C207.45,493.23 198.58,491.8 198.58,491.8 C198.58,491.8 189.71,490.37 189.71,490.37 C189.71,490.37 180.99,488.21 180.99,488.21 C180.99,488.21 172.31,485.89 172.31,485.89 C172.31,485.89 163.63,483.57 163.63,483.57 C163.63,483.57 155.19,480.5 155.19,480.5 C155.19,480.5 146.78,477.32 146.78,477.32 C146.78,477.32 138.37,474.15 138.37,474.15 C138.37,474.15 130.11,470.63 130.11,470.63 C130.11,470.63 121.86,467.06 121.86,467.06 C121.86,467.06 113.62,463.48 113.62,463.48 C113.62,463.48 105.38,459.9 105.38,459.9 C105.38,459.9 97.04,456.56 97.04,456.56 C97.04,456.56 88.63,453.39 88.63,453.39 C88.63,453.39 80.22,450.22 80.22,450.22 C80.22,450.22 71.6,447.7 71.6,447.7 C71.6,447.7 62.92,445.37 62.92,445.37 C62.92,445.37 54.24,443.05 54.24,443.05 C54.24,443.05 45.38,441.55 45.38,441.55 C45.38,441.55 36.52,440.1 36.52,440.1 C36.52,440.1 27.63,438.78 27.63,438.78 C27.63,438.78 18.66,438.2 18.66,438.2 C18.66,438.2 9.7,437.61 9.7,437.61 C9.7,437.61 0.72,437.36 0.72,437.36 C0.72,437.36 -8.26,437.65 -8.26,437.65 C-8.26,437.65 -17.24,437.95 -17.24,437.95 C-17.24,437.95 -26.18,438.77 -26.18,438.77 C-26.18,438.77 -35.09,439.94 -35.09,439.94 C-35.09,439.94 -44,441.1 -44,441.1 C-44,441.1 -52.78,442.98 -52.78,442.98 C-52.78,442.98 -61.53,445.02 -61.53,445.02 C-61.53,445.02 -70.28,447.07 -70.28,447.07 C-70.28,447.07 -78.84,449.81 -78.84,449.81 C-78.84,449.81 -87.37,452.64 -87.37,452.64 C-87.37,452.64 -95.72,455.95 -95.72,455.95 C-95.72,455.95 -104.05,459.32 -104.05,459.32 C-104.05,459.32 -112.29,462.9 -112.29,462.9 C-112.29,462.9 -120.53,466.48 -120.53,466.48 C-120.53,466.48 -128.78,470.06 -128.78,470.06 C-128.78,470.06 -137.02,473.63 -137.02,473.63 C-137.02,473.63 -145.43,476.81 -145.43,476.81 C-145.43,476.81 -153.84,479.98 -153.84,479.98 C-153.84,479.98 -162.24,483.15 -162.24,483.15 C-162.24,483.15 -170.91,485.52 -170.91,485.52 C-170.91,485.52 -179.59,487.83 -179.59,487.83 C-179.59,487.83 -188.28,490.13 -188.28,490.13 C-188.28,490.13 -197.15,491.56 -197.15,491.56 C-197.15,491.56 -206.02,492.99 -206.02,492.99 C-206.02,492.99 -214.91,494.27 -214.91,494.27 C-214.91,494.27 -223.88,494.8 -223.88,494.8 C-223.88,494.8 -232.85,495.33 -232.85,495.33 C-232.85,495.33 -241.83,495.5 -241.83,495.5 C-241.83,495.5 -250.81,495.13 -250.81,495.13 C-250.81,495.13 -259.79,494.75 -259.79,494.75 C-259.79,494.75 -268.71,493.79 -268.71,493.79 C-268.71,493.79 -277.61,492.53 -277.61,492.53 C-277.61,492.53 -286.51,491.27 -286.51,491.27 C-286.51,491.27 -295.24,489.17 -295.24,489.17 C-295.24,489.17 -303.98,487.06 -303.98,487.06 C-303.98,487.06 -312.63,484.67 -312.63,484.67 C-312.63,484.67 -321.12,481.74 -321.12,481.74 C-321.12,481.74 -329.62,478.8 -329.62,478.8 C-329.62,478.8 -337.9,475.33 -337.9,475.33 C-337.9,475.33 -346.08,471.62 -346.08,471.62 C-346.08,471.62 -354.24,467.85 -354.24,467.85 C-354.24,467.85 -362.05,463.41 -362.05,463.41 C-362.05,463.41 -369.86,458.96 -369.86,458.96 C-369.86,458.96 -377.47,454.21 -377.47,454.21 C-377.47,454.21 -384.85,449.08 -384.85,449.08 C-384.85,449.08 -392.23,443.95 -392.23,443.95 C-392.23,443.95 -399.2,438.29 -399.2,438.29 C-399.2,438.29 -406.09,432.52 -406.09,432.52 C-406.09,432.52 -412.86,426.62 -412.86,426.62 C-412.86,426.62 -419.22,420.27 -419.22,420.27 C-419.22,420.27 -425.57,413.91 -425.57,413.91 C-425.57,413.91 -431.57,407.23 -431.57,407.23 C-431.57,407.23 -437.33,400.34 -437.33,400.34 C-437.33,400.34 -443.1,393.44 -443.1,393.44 C-443.1,393.44 -448.23,386.07 -448.23,386.07 C-448.23,386.07 -453.36,378.69 -453.36,378.69 C-453.36,378.69 -458.23,371.15 -458.23,371.15 C-458.23,371.15 -462.67,363.33 -462.67,363.33 C-462.67,363.33 -467.12,355.53 -467.12,355.53 C-467.12,355.53 -471,347.43 -471,347.43 C-471,347.43 -474.72,339.25 -474.72,339.25 C-474.72,339.25 -478.32,331.02 -478.32,331.02 C-478.32,331.02 -481.25,322.52 -481.25,322.52 C-481.25,322.52 -484.19,314.03 -484.19,314.03 C-484.19,314.03 -486.71,305.42 -486.71,305.42 C-486.71,305.42 -488.82,296.68 -488.82,296.68 C-488.82,296.68 -490.94,287.95 -490.94,287.95 C-490.94,287.95 -492.32,279.07 -492.32,279.07 C-492.32,279.07 -493.58,270.18 -493.58,270.18 C-493.58,270.18 -494.69,261.27 -494.69,261.27 C-494.69,261.27 -495.07,252.29 -495.07,252.29 C-495.07,252.29 -495.44,243.31 -495.44,243.31 C-495.44,243.31 -495.42,234.33 -495.42,234.33 C-495.42,234.33 -494.89,225.36 -494.89,225.36 C-494.89,225.36 -494.36,216.39 -494.36,216.39 C-494.36,216.39 -493.23,207.49 -493.23,207.49 C-493.23,207.49 -491.8,198.61 -491.8,198.61 C-491.8,198.61 -490.37,189.74 -490.37,189.74 C-490.37,189.74 -488.22,181.02 -488.22,181.02 C-488.22,181.02 -485.9,172.34 -485.9,172.34 C-485.9,172.34 -483.58,163.66 -483.58,163.66 C-483.58,163.66 -480.51,155.22 -480.51,155.22 C-480.51,155.22 -477.34,146.81 -477.34,146.81 C-477.34,146.81 -474.17,138.41 -474.17,138.41 C-474.17,138.41 -470.65,130.14 -470.65,130.14 C-470.65,130.14 -467.07,121.9 -467.07,121.9 C-467.07,121.9 -463.49,113.65 -463.49,113.65 C-463.49,113.65 -459.91,105.41 -459.91,105.41 C-459.91,105.41 -456.57,97.07 -456.57,97.07 C-456.57,97.07 -453.4,88.66 -453.4,88.66 C-453.4,88.66 -450.23,80.25 -450.23,80.25 C-450.23,80.25 -447.7,71.64 -447.7,71.64 C-447.7,71.64 -445.38,62.96 -445.38,62.96 C-445.38,62.96 -443.06,54.28 -443.06,54.28 C-443.06,54.28 -441.56,45.42 -441.56,45.42 C-441.56,45.42 -440.1,36.55 -440.1,36.55 C-440.1,36.55 -438.78,27.67 -438.78,27.67 C-438.78,27.67 -438.2,18.7 -438.2,18.7 C-438.2,18.7 -437.62,9.73 -437.62,9.73 C-437.62,9.73 -437.36,0.76 -437.36,0.76 C-437.36,0.76 -437.66,-8.22 -437.66,-8.22 C-437.66,-8.22 -437.95,-17.2 -437.95,-17.2 C-437.95,-17.2 -438.77,-26.14 -438.77,-26.14 C-438.77,-26.14 -439.93,-35.05 -439.93,-35.05 C-439.93,-35.05 -441.1,-43.96 -441.1,-43.96 C-441.1,-43.96 -442.98,-52.75 -442.98,-52.75 C-442.98,-52.75 -445.01,-61.5 -445.01,-61.5 C-445.01,-61.5 -447.06,-70.25 -447.06,-70.25 C-447.06,-70.25 -449.8,-78.81 -449.8,-78.81 C-449.8,-78.81 -452.63,-87.33 -452.63,-87.33 C-452.63,-87.33 -455.94,-95.69 -455.94,-95.69 C-455.94,-95.69 -459.31,-104.02 -459.31,-104.02 C-459.31,-104.02 -462.89,-112.26 -462.89,-112.26 C-462.89,-112.26 -466.47,-120.5 -466.47,-120.5 C-466.47,-120.5 -470.05,-128.74 -470.05,-128.74 C-470.05,-128.74 -473.68,-137.12 -473.68,-137.12 C-473.68,-137.12 -476.85,-145.53 -476.85,-145.53 C-476.85,-145.53 -480.03,-153.94 -480.03,-153.94 C-480.03,-153.94 -483.2,-162.34 -483.2,-162.34 C-483.2,-162.34 -485.55,-171.02 -485.55,-171.02 C-485.55,-171.02 -487.86,-179.7 -487.86,-179.7 C-487.86,-179.7 -490.15,-188.39 -490.15,-188.39 C-490.15,-188.39 -491.58,-197.26 -491.58,-197.26 C-491.58,-197.26 -493.01,-206.13 -493.01,-206.13 C-493.01,-206.13 -494.28,-215.02 -494.28,-215.02 C-494.28,-215.02 -494.81,-223.99 -494.81,-223.99 C-494.81,-223.99 -495.33,-232.96 -495.33,-232.96 C-495.33,-232.96 -495.5,-241.94 -495.5,-241.94 C-495.5,-241.94 -495.12,-250.92 -495.12,-250.92 C-495.12,-250.92 -494.75,-259.9 -494.75,-259.9 C-494.75,-259.9 -493.78,-268.82 -493.78,-268.82 C-493.78,-268.82 -492.52,-277.72 -492.52,-277.72 C-492.52,-277.72 -491.26,-286.61 -491.26,-286.61 C-491.26,-286.61 -489.15,-295.35 -489.15,-295.35 C-489.15,-295.35 -487.03,-304.08 -487.03,-304.08 C-487.03,-304.08 -484.64,-312.73 -484.64,-312.73 C-484.64,-312.73 -481.7,-321.23 -481.7,-321.23 C-481.7,-321.23 -478.77,-329.72 -478.77,-329.72 C-478.77,-329.72 -475.29,-338 -475.29,-338 C-475.29,-338 -471.57,-346.18 -471.57,-346.18 C-471.57,-346.18 -467.8,-354.33 -467.8,-354.33 C-467.8,-354.33 -463.36,-362.14 -463.36,-362.14 C-463.36,-362.14 -458.91,-369.95 -458.91,-369.95 C-458.91,-369.95 -454.15,-377.56 -454.15,-377.56 C-454.15,-377.56 -449.02,-384.94 -449.02,-384.94 C-449.02,-384.94 -443.88,-392.32 -443.88,-392.32 C-443.88,-392.32 -438.22,-399.28 -438.22,-399.28 C-438.22,-399.28 -432.45,-406.18 -432.45,-406.18 C-432.45,-406.18 -426.55,-412.94 -426.55,-412.94 C-426.55,-412.94 -420.19,-419.3 -420.19,-419.3 C-420.19,-419.3 -413.84,-425.65 -413.84,-425.65 C-413.84,-425.65 -407.15,-431.64 -407.15,-431.64 C-407.15,-431.64 -400.26,-437.41 -400.26,-437.41 C-400.26,-437.41 -393.36,-443.16 -393.36,-443.16 C-393.36,-443.16 -385.98,-448.29 -385.98,-448.29 C-385.98,-448.29 -378.6,-453.43 -378.6,-453.43 C-378.6,-453.43 -371.05,-458.28 -371.05,-458.28 C-371.05,-458.28 -363.24,-462.73 -363.24,-462.73 C-363.24,-462.73 -355.43,-467.18 -355.43,-467.18 C-355.43,-467.18 -347.33,-471.05 -347.33,-471.05 C-347.33,-471.05 -339.15,-474.76 -339.15,-474.76 C-339.15,-474.76 -330.92,-478.35 -330.92,-478.35 C-330.92,-478.35 -322.42,-481.29 -322.42,-481.29 C-322.42,-481.29 -313.93,-484.23 -313.93,-484.23 C-313.93,-484.23 -305.31,-486.73 -305.31,-486.73 C-305.31,-486.73 -296.58,-488.85 -296.58,-488.85 C-296.58,-488.85 -287.85,-490.97 -287.85,-490.97 C-287.85,-490.97 -278.97,-492.34 -278.97,-492.34 C-278.97,-492.34 -270.07,-493.6 -270.07,-493.6 C-270.07,-493.6 -261.16,-494.7 -261.16,-494.7 C-261.16,-494.7 -252.18,-495.07 -252.18,-495.07 C-252.18,-495.07 -243.2,-495.44 -243.2,-495.44 C-243.2,-495.44 -234.23,-495.41 -234.23,-495.41 C-234.23,-495.41 -225.26,-494.88 -225.26,-494.88 C-225.26,-494.88 -216.29,-494.35 -216.29,-494.35 C-216.29,-494.35 -207.38,-493.22 -207.38,-493.22 C-207.38,-493.22 -198.51,-491.79 -198.51,-491.79 C-198.51,-491.79 -189.64,-490.36 -189.64,-490.36 C-189.64,-490.36 -180.92,-488.19 -180.92,-488.19 C-180.92,-488.19 -172.24,-485.87 -172.24,-485.87 C-172.24,-485.87 -163.56,-483.56 -163.56,-483.56 C-163.56,-483.56 -155.12,-480.47 -155.12,-480.47 C-155.12,-480.47 -146.72,-477.3 -146.72,-477.3 C-146.72,-477.3 -138.31,-474.13 -138.31,-474.13 C-138.31,-474.13 -130.04,-470.61 -130.04,-470.61 C-130.04,-470.61 -121.8,-467.03 -121.8,-467.03 C-121.8,-467.03 -113.55,-463.45 -113.55,-463.45 C-113.55,-463.45 -105.31,-459.87 -105.31,-459.87 C-105.31,-459.87 -96.97,-456.53 -96.97,-456.53 C-96.97,-456.53 -88.56,-453.37 -88.56,-453.37 C-88.56,-453.37 -80.15,-450.2 -80.15,-450.2 C-80.15,-450.2 -71.53,-447.68 -71.53,-447.68 C-71.53,-447.68 -62.85,-445.36 -62.85,-445.36 C-62.85,-445.36 -54.17,-443.04 -54.17,-443.04 C-54.17,-443.04 -45.31,-441.54 -45.31,-441.54 C-45.31,-441.54 -36.44,-440.09 -36.44,-440.09 C-36.44,-440.09 -27.56,-438.78 -27.56,-438.78 C-27.56,-438.78 -18.59,-438.19 -18.59,-438.19 C-18.59,-438.19 -9.62,-437.61 -9.62,-437.61 C-9.62,-437.61 -0.65,-437.37 -0.65,-437.37c " />
- </group>
- </group>
- <group android:name="time_group" />
- </vector>
- </aapt:attr>
-</animated-vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index b3f32a2863a8..5e8a8a570466 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -34,13 +34,14 @@
android:layout_height="match_parent"
android:layout_gravity="center_vertical">
- <TextView
+ <com.android.systemui.qs.BuildTextView
android:id="@+id/build"
android:layout_width="0dp"
android:layout_height="match_parent"
android:paddingEnd="4dp"
android:layout_weight="1"
- android:clickable="true"
+ android:marqueeRepeatLimit="1"
+ android:clickable="false"
android:ellipsize="marquee"
android:focusable="true"
android:gravity="center_vertical"
diff --git a/packages/SystemUI/res/layout/volume_dialog_slider.xml b/packages/SystemUI/res/layout/volume_dialog_slider.xml
index 6eb7b730e105..c5f468e731f5 100644
--- a/packages/SystemUI/res/layout/volume_dialog_slider.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_slider.xml
@@ -14,8 +14,8 @@
limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="0dp"
- android:layout_height="0dp"
+ android:layout_width="@dimen/volume_dialog_slider_width"
+ android:layout_height="match_parent"
android:maxHeight="@dimen/volume_dialog_slider_height">
<com.google.android.material.slider.Slider
diff --git a/packages/SystemUI/res/layout/window_magnification_settings_view.xml b/packages/SystemUI/res/layout/window_magnification_settings_view.xml
index afd4fa7a5edd..7f7350472fa5 100644
--- a/packages/SystemUI/res/layout/window_magnification_settings_view.xml
+++ b/packages/SystemUI/res/layout/window_magnification_settings_view.xml
@@ -132,7 +132,8 @@
android:layout_height="wrap_content"
android:track="@drawable/settingslib_track_selector"
android:thumb="@drawable/settingslib_thumb_selector"
- android:theme="@style/MainSwitch.Settingslib"/>
+ android:theme="@style/MainSwitch.Settingslib"
+ android:minHeight="48dp" />
</LinearLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 0e8b2d53598e..5e7d9c4a041b 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelliet, goeie toestand"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelliet, verbinding is beskikbaar"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelliet-SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Noodoproepe of SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"geen sein nie"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"een staaf"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"gaan by toestel in"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gebruik vingerafdruk om oop te maak"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Stawing word vereis. Raak die vingerafdruksensor om te staaf."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Oproep aan die gang"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiele data"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Gekoppel"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Tydelik gekoppel"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Huidige app"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Toeganklikheid"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Kortpadsleutels"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Pasmaak kortpadsleutels"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Pasmaak kortpaaie"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Verwyder kortpad?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Stel terug na verstek?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Druk sleutel om kortpad toe te wys"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Sleutelkombinasie is reeds in gebruik. Probeer ’n ander sleutel."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Kortpad kan nie gestel word nie."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Voeg kortpad by"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Vee kortpad uit"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigeer met jou sleutelbord"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Leer kortpadsleutels"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigeer met jou raakpaneel"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 15286a6aaea2..d969525b7c4a 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ሳተላይት፣ ጥሩ ግንኙነት"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ሳተላይት፣ ግንኙነት አለ"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"ሳተላይት ኤስኦኤስ"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"የአደጋ ጥሪዎች ወይም ኤስኦኤስ"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>፣ <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>።"</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"ምንም ምልክት የለም"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"አንድ አሞሌ"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"መሣሪያን ያስገቡ"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ለመክፈት የጣት አሻራ ይጠቀሙ"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ማረጋገጥ ያስፈልጋል። ለማረጋገጥ የጣት አሻራ ዳሳሹን ይንኩ።"</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"እየተካሄደ ያለ ጥሪ"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"የተንቀሳቃሽ ስልክ ውሂብ"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"ተገናኝቷል"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"በጊዜያዊነት ተገናኝቷል"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"የአሁን መተግበሪያ"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ተደራሽነት"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"የቁልፍ ሰሌዳ አቋራጮች"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"የቁልፍ ሰሌዳ አቋራጮችን ያብጁ"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"አቋራጮችን ያብጁ"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"አቋራጭ ይወገድ?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ወደ ነባሪ ዳግም ይጀመር?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"አቋራጭ ለመመደብ ቁልፍ ይጫኑ"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"የቁልፍ ጥምረት አስቀድሞ በሥራ ላይ ነው። ሌላ ቁልፍ ይሞክሩ።"</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"አቋራጩ ሊቀናበር አይችልም።"</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"አቋራጭ አክል"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"አቋረጭ ሰርዝ"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"የቁልፍ ሰሌዳዎን በመጠቀም ያስሱ"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"የቁልፍ ሰሌዳ አቋራጮችን ይወቁ"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"የመዳሰሻ ሰሌዳዎን በመጠቀም ያስሱ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index d68c43281908..d46df1d8b348 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"قمر صناعي، الاتصال جيد"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"قمر صناعي، الاتصال متوفّر"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"اتصالات الطوارئ بالقمر الصناعي"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"مكالمات الطوارئ أو ميزة \"اتصالات طوارئ بالقمر الصناعي\""</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"‫\"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>\"، <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"ما مِن أشرطة إشارة"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"شريط إشارة واحد"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"الدخول إلى الجهاز"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"يمكنك استخدام بصمة الإصبع للفتح"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"المصادقة مطلوبة. المس مستشعر بصمات الإصبع للمصادقة."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"مكالمة جارية"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"بيانات الجوّال"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"متصلة بالإنترنت"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"متصلة مؤقتًا"</string>
@@ -1437,7 +1437,8 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"التطبيق الحالي"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"تسهيل الاستخدام"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"اختصارات لوحة المفاتيح"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"تخصيص اختصارات لوحة المفاتيح"</string>
+ <!-- no translation found for shortcut_helper_customize_mode_title (8327297960035006036) -->
+ <skip />
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"هل تريد إزالة هذا الاختصار؟"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"يُرجى تأكيد إعادة الضبط على الإعدادات التلقائية"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"اضغط على مفتاح لتخصيص الاختصار"</string>
@@ -1465,6 +1466,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"يتم حاليًا استخدام مجموعة المفاتيح هذه. يُرجى تجربة مفتاح آخر."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"تعذَّر ضبط الاختصار."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"إضافة اختصار"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"حذف الاختصار"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"التنقّل باستخدام لوحة المفاتيح"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"تعرَّف على اختصارات لوحة المفاتيح"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"التنقّل باستخدام لوحة اللمس"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 4c4579f8e42d..ff5e2106a8d2 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"উপগ্ৰহ, ভাল সংযোগ"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"উপগ্ৰহ, সংযোগ উপলব্ধ"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"উপগ্ৰহ SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"জৰুৰীকালীন কল বা SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"কোনো ছিগনেল নাই"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"এডাল দণ্ড"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ডিভাইচ আনলক কৰক"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"খুলিবলৈ ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"বিশ্বাসযোগ্যতা প্ৰমাণীকৰণৰ আৱশ্যক। বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰিবলৈ ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো স্পৰ্শ কৰক।"</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"চলি থকা কল"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"ম’বাইল ডেটা"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"সংযোজিত হৈ আছে"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"অস্থায়ীভাৱে সংযোগ কৰা হৈছে"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"বৰ্তমানৰ এপ্‌"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"সাধ্য সুবিধা"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"কীব’ৰ্ডৰ শ্বৰ্টকাট"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"কীব’ৰ্ডৰ শ্বৰ্টকাট কাষ্টমাইজ কৰক"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"শ্বৰ্টকাট কাষ্টমাইজ কৰক"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"শ্বৰ্টকাট আঁতৰাবনে?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ডিফ\'ল্ট হিচাপে পুনৰ ৰিছেট কৰিবনে?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"শ্বৰ্টকাটৰ ভূমিকা অৰ্পণ কৰিবলৈ কী টিপক"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"কীৰ মিশ্ৰণ ইতিমধ্যে ব্যৱহাৰ হৈ আছে। অন্য এটা কী ব্যৱহাৰ কৰি চাওক।"</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"শ্বৰ্টকাট ছেট কৰিব নোৱাৰি।"</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"শ্বৰ্টকাট যোগ দিয়ক"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"শ্বৰ্টকাট মচক"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"কীব’ৰ্ড ব্যৱহাৰ কৰি নেভিগে’ট কৰক"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"কীব’ৰ্ডৰ শ্বৰ্টকাটসমূহৰ বিষয়ে জানক"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"আপোনাৰ টাচ্চপেড ব্যৱহাৰ কৰি নেভিগে’ট কৰক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 08452d353765..dbeacf0bf277 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Peyk, bağlantı yaxşıdır"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Peyk, bağlantı var"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Təcili peyk bağlantısı"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Təcili zənglər və ya SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"siqnal yoxdur"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"bir zolaq"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"cihaz daxil edin"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Açmaq üçün barmaq izindən istifadə edin"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Doğrulanma tələb olunur. Doğrulamaq üçün barmaq izi sensoruna toxunun."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Davam edən zəng"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobil data"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Qoşulub"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Müvəqqəti qoşulub"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Cari tətbiq"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Xüsusi imkanlar"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Klaviatura qısayolları"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Klaviatura qısayollarını fərdiləşdirin"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Qısayolları fərdiləşdirin"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Qısayol silinsin?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Defolt vəziyyətə qaytarılsın?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Qısayol təyin etmək üçün düyməni basın"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Düymə kombinasiyası artıq istifadə olunur. Başqa düyməni sınayın."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Qısayol ayarlana bilməz."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Qısayol əlavə edin"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Qısayolu silin"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Klaviaturadan istifadə edərək hərəkət edin"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Klaviatura qısayolları haqqında öyrənin"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Taçpeddən istifadə edərək hərəkət edin"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 8d9495a1a4e7..ca01a3d89ebe 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, veza je dobra"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, veza je dostupna"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Hitna pomoć preko satelita"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Hitni pozivi ili hitna pomoć"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"nema signala"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"jedna crta"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"unesite uređaj"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorite pomoću otiska prsta"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Potrebna je potvrda identiteta. Dodirnite senzor za otisak prsta da biste potvrdili identitet."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Poziv je u toku"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilni podaci"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Privremeno povezano"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktuelna aplikacija"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Pristupačnost"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Tasterske prečice"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prilagodite tasterske prečice"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Prilagodite prečice"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Želite da uklonite prečicu?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Želite da resetujete na podrazumevano?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pritisnite taster da biste dodelili prečicu"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Kombinacija tastera se već koristi. Probajte sa drugim tasterom."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Podešavanje prečice nije uspelo."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Dodajte prečicu"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Izbrišite prečicu"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Krećite se pomoću tastature"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Saznajte više o tasterskim prečicama"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Krećite se pomoću tačpeda"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 3431862c77fc..40d78c20859b 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Спадарожнікавая сувязь, добрае падключэнне"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Спадарожнікавая сувязь, падключэнне даступнае"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Экстраннае спадарожнікавае падключэнне"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Экстранныя выклікі або экстраннае спадарожнікавае падключэнне"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"няма сігналу"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"адзiн слупок"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"адкрыць галоўны экран прылады"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Каб адкрыць, скарыстайце адбітак пальца"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Патрабуецца аўтэнтыфікацыя. Дакраніцеся да сканера адбіткаў пальцаў."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Актыўны выклік"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мабільная перадача даных"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Падключана"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Падключана часова"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Бягучая праграма"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Спецыяльныя магчымасці"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Спалучэнні клавіш"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Наладзіць спалучэнні клавіш"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Наладзіць спалучэнні клавіш"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Выдаліць спалучэнне клавіш?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Скінуць налады да стандартных?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Націсніце клавішу, каб прызначыць спалучэнне клавіш"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Гэта спалучэнне клавіш ужо выкарыстоўваецца. Паспрабуйце іншую клавішу."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Не ўдаецца наладзіць спалучэнне клавіш."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Дадаць ярлык"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Выдаліць спалучэнне клавіш"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Навігацыя з дапамогай клавіятуры"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Азнаёмцеся са спалучэннямі клавіш"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Навігацыя з дапамогай сэнсарнай панэлі"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 1128d03595e1..95037ab4d29e 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Сателит, добра връзка"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Сателит, налице е връзка"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS чрез сателит"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Спешни обаждания или SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"няма сигнал"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"една чертичка"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"вход в устройството"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Използвайте отпечатък за отваряне"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Изисква се удостоверяване на самоличността. За целта докоснете сензора за отпечатъци."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Текущо обаждане"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилни данни"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Свързано"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Установена е временна връзка"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Текущо приложение"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Достъпност"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Клавишни комбинации"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Персонализиране на клавишните комбинации"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Персонализиране на преките пътища"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Да се премахне ли клавишната комбинация?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Да се възстановят ли стандартните настройки?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Натиснете клавиш, за да зададете клавишна комбинация"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Клавишната комбинация вече се използва. Опитайте с друг клавиш."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Прекият път не може да се зададе."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Добавяне на пряк път"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Изтриване на прекия път"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Навигирайте посредством клавиатурата си"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Научете за клавишните комбинации"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Навигирайте посредством сензорния панел"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 23a693b9840e..73eddf28bbed 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"স্যাটেলাইট, ভালো কানেকশন"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"স্যাটেলাইট, কানেকশন উপলভ্য আছে"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"স্যাটেলাইট SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"জরুরি কল বা SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>।"</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"কোনও সিগন্যাল নেই"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"একটি বার"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ডিভাইস আনলক করুন"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"খুলতে ফিঙ্গারপ্রিন্ট ব্যবহার করুন"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"যাচাইকরণ করতে হবে। যাচাইকরণ করতে আঙুলের ছাপের সেন্সরে টাচ করুন।"</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"চালু থাকা কল"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"মোবাইল ডেটা"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"কানেক্ট করা আছে"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"সাময়িকভাবে কানেক্ট করা হয়েছে"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"বর্তমান অ্যাপ"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"অ্যাক্সেসিবিলিটি"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"কীবোর্ড শর্টকাট"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"কীবোর্ড শর্টকাট কাস্টমাইজ করুন"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"শর্টকাট কাস্টমাইজ করুন"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"শর্টকাট সরাবেন?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ডিফল্ট শর্টকার্ট আবার রিসেট করতে চান?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"শর্টকাট অ্যাসাইন করতে কী প্রেস করুন"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"কী কম্বিনেশন আগে থেকে ব্যবহার হচ্ছে। অন্য কী ব্যবহার করে দেখুন।"</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"শর্টকাট সেট করা যায়নি।"</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"শর্টকাট যোগ করুন"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"শর্টকাট মুছুন"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"আপনার কীবোর্ড ব্যবহার করে নেভিগেট করুন"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"কীবোর্ড শর্টকাট সম্পর্কে জানুন"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"আপনার টাচপ্যাড ব্যবহার করে নেভিগেট করুন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index d7b3f60edb03..c16627f86820 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -348,7 +348,7 @@
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Neimenovani uređaj"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nema dostupnih uređaja"</string>
<string name="quick_settings_cast_no_network" msgid="3863016850468559522">"Nema WiFi-ja ni Ethernet veze"</string>
- <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Osvjetljenje"</string>
+ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Osvijetljenost"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzija boja"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Ispravka boja"</string>
<string name="quick_settings_font_scaling_label" msgid="5289001009876936768">"Veličina fonta"</string>
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, dobra veza"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, veza je dostupna"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Hitna pomoć putem satelita"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Hitni pozivi ili pomoć"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"nema signala"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"jedna crtica"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"pristup uređaju"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorite pomoću otiska prsta"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Potrebna je autentifikacija. Dodirnite senzor za otisak prsta da autentificirate."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Poziv u toku"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Prijenos podataka na mobilnoj mreži"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Privremeno povezano"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Trenutna aplikacija"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Pristupačnost"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Prečice na tastaturi"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prilagodite prečice na tastaturi"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Prilagodite prečice"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Ukloniti prečicu?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Vratiti na zadano?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pritisnite tipku da dodijelite prečicu"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Ta se kombinacija tipki već koristi. Pokušajte s drugom tipkom."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Prečica se ne može postaviti."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Dodavanje prečice"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Brisanje prečice"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Krećite se pomoću tastature"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Saznajte više o prečicama tastature"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Krećite se pomoću dodirne podloge"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 09f63c551f01..43ba8fac3dad 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satèl·lit, bona connexió"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satèl·lit, connexió disponible"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS per satèl·lit"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Trucades d\'emergència o SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"no hi ha senyal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"una barra"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"accedir al dispositiu"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Utilitza l\'empremta digital per obrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticació necessària. Toca el sensor d\'empremtes digitals per autenticar-te."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Trucada en curs"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Dades mòbils"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connectat"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Connexió temporal"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aplicació actual"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibilitat"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Tecles de drecera"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalitza les tecles de drecera"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalitza les dreceres"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Vols suprimir la drecera?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Vols restablir els valors predeterminats?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Prem la tecla per assignar la drecera"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"La combinació de tecles ja s\'està utilitzant. Prova-ho amb una altra tecla."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"No es pot configurar la drecera."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Afegeix una drecera"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Suprimeix la drecera"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navega amb el teclat"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprèn les tecles de drecera"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navega amb el ratolí tàctil"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 07587641802a..17945a3856d6 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, dobré připojení"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, připojení je k dispozici"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS přes satelit"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Tísňová volání nebo SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"není signál"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"jedna čárka"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"zadáte zařízení"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"K otevření použijte otisk prstu"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Je vyžadováno ověření. Dotkněte se snímače otisků prstů."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Probíhající hovor"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilní data"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Připojeno"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Dočasně připojeno"</string>
@@ -1437,7 +1437,8 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktuální aplikace"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Přístupnost"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Klávesové zkratky"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Přizpůsobení klávesových zkratek"</string>
+ <!-- no translation found for shortcut_helper_customize_mode_title (8327297960035006036) -->
+ <skip />
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Odstranit zkratku?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Resetovat do výchozího nastavení?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Nastavte zkratku stisknutím klávesy"</string>
@@ -1465,6 +1466,10 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Kombinace kláves se už používá. Použijte jinou klávesu."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Zkratku není možné nastavit."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <!-- no translation found for shortcut_helper_add_shortcut_button_label (7655779534665954910) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_delete_shortcut_button_label (3148773472696137052) -->
+ <skip />
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigujte pomocí klávesnice"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Naučte se klávesové zkratky"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigujte pomocí touchpadu"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index bcf93657caa7..1f8c8659b9cf 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellit – god forbindelse"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellit – forbindelsen er tilgængelig"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS-meldinger via satellit"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Nødopkald eller SOS-meldinger via satellit"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"intet signal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"én bjælke"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"få adgang til enheden"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Brug fingeraftryk for at åbne"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Godkendelse er påkrævet. Sæt fingeren på fingeraftrykssensoren for at godkende."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Igangværende opkald"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobildata"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Forbundet"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Midlertidigt forbundet"</string>
@@ -1437,13 +1437,13 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktuel app"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Hjælpefunktioner"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Tastaturgenveje"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Tilpas tastaturgenveje"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Tilpas genveje"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Skal genvejen fjernes?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Vil du nulstille til standard?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Tryk på en tast for at tildele genvej"</string>
<string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Denne handling sletter din tilpassede genvej permanent."</string>
<string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Denne handling sletter alle dine tilpassede genveje permanent."</string>
- <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Genveje til søgning"</string>
+ <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Søg efter genveje"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Der er ingen søgeresultater"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikon for Skjul"</string>
<string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ikon for handlingstast eller metatast"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Tastekombinationen er allerede i brug. Prøv en anden tast."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Genvejen kan ikke konfigureres."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Tilføj genvej"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Slet genvej"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviger ved hjælp af dit tastatur"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Se tastaturgenveje"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviger ved hjælp af din touchplade"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 670f5a712c4a..213955839a71 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellit, Verbindung gut"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellit, Verbindung verfügbar"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Notruf über Satellit"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Notrufe oder SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"kein Empfang"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"ein Balken"</string>
@@ -871,7 +872,7 @@
<string name="keyboard_shortcut_a11y_filter_input" msgid="4589316004510335529">"Tastenkombinationen für die Eingabe werden angezeigt"</string>
<string name="keyboard_shortcut_a11y_filter_open_apps" msgid="6175417687221004059">"Tastenkombinationen zum Öffnen von Apps werden angezeigt"</string>
<string name="keyboard_shortcut_a11y_filter_current_app" msgid="7944592357493737911">"Tastenkombinationen für die aktuelle App werden angezeigt"</string>
- <string name="group_system_access_notification_shade" msgid="1619028907006553677">"Benachrichti­gungen ansehen"</string>
+ <string name="group_system_access_notification_shade" msgid="1619028907006553677">"Benachrichti­gun­gen ansehen"</string>
<string name="group_system_full_screenshot" msgid="5742204844232667785">"Screenshot erstellen"</string>
<string name="group_system_access_system_app_shortcuts" msgid="8562482996626694026">"Tasten­kürzel anzeigen"</string>
<string name="group_system_go_back" msgid="2730322046244918816">"Zurück"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"Eingeben des Geräts"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Mit Fingerabdruck öffnen"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentifizierung erforderlich. Tippe dazu einfach auf den Fingerabdrucksensor."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Aktiver Anruf"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile Daten"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Verbunden"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Vorübergehend verbunden"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktuelle App"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Bedienungshilfen"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Tastenkürzel"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Tastenkürzel anpassen"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Tastenkombinationen anpassen"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Tastaturkürzel entfernen?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Auf Standardeinstellung zurücksetzen?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Drücke eine Taste, um das Tastaturkürzel einzurichten"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Diese Tastenkombination wird bereits verwendet. Versuche es mit einer anderen Taste."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Die Tastenkombination kann nicht festgelegt werden."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Verknüpfung hinzufügen"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Verknüpfung löschen"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigation mit der Tastatur"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Informationen zu Tastenkombinationen"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigation mit dem Touchpad"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 31e356797f68..589298ea616b 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Δορυφορική, καλή σύνδεση"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Δορυφορική, διαθέσιμη σύνδεση"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Δορυφορικό SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Κλήσεις έκτακτης ανάγκης ή SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"δεν υπάρχει σήμα"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"μία γραμμή"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"εισαγωγή συσκευής"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Χρήση δακτυλικού αποτυπώματος για άνοιγμα"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Απαιτείται έλεγχος ταυτότητας. Αγγίξτε τον αισθητήρα δακτυλικών αποτυπωμάτων για έλεγχο ταυτότητας."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Κλήση σε εξέλιξη"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Δεδομένα κινητής τηλεφωνίας"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Συνδέθηκε"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Προσωρινή σύνδεση"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Τρέχουσα εφαρμογή"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Προσβασιμότητα"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Συντομεύσεις πληκτρολογίου"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Προσαρμογή συντομεύσεων πληκτρολογίου"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Προσαρμογή συντομεύσεων"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Κατάργηση συντόμευσης;"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Επαναφορά στις προεπιλογές;"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Πατήστε το πλήκτρο για ανάθεση της συντόμευσης"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Ο συνδυασμός πλήκτρων χρησιμοποιείται ήδη. Δοκιμάστε άλλο πλήκτρο."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Δεν είναι δυνατή η ρύθμιση της συντόμευσης."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Προσθήκη συντόμευσης"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Διαγραφή συντόμευσης"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Πλοήγηση με το πληκτρολόγιο"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Μάθετε συντομεύσεις πληκτρολογίου"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Πλοήγηση με την επιφάνεια αφής"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 30eb21f9308f..f31e51f7f3da 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellite, good connection"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellite, connection available"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Emergency calls or SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"No signal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"one bar"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"enter device"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Ongoing call"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Temporarily connected"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Current app"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibility"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Keyboard shortcuts"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Customise keyboard shortcuts"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Customise shortcuts"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Remove shortcut?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Reset back to default?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Press key to assign shortcut"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Key combination already in use. Try another key."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Shortcut cannot be set."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Add shortcut"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Delete shortcut"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigate using your keyboard"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Learn keyboards shortcuts"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigate using your touchpad"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 4b4b7b8e4575..be09504a5cd6 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellite, good connection"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellite, connection available"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Emergency calls or SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"no signal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"one bar"</string>
@@ -1436,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Current App"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibility"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Keyboard shortcuts"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Customize keyboard shortcuts"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Customize shortcuts"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Remove shortcut?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Reset back to default?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Press key to assign shortcut"</string>
@@ -1464,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Key combination already in use. Try another key."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Shortcut cannot be set."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Add shortcut"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Delete shortcut"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigate using your keyboard"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Learn keyboards shortcuts"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigate using your touchpad"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 30eb21f9308f..f31e51f7f3da 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellite, good connection"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellite, connection available"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Emergency calls or SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"No signal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"one bar"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"enter device"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Ongoing call"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Temporarily connected"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Current app"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibility"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Keyboard shortcuts"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Customise keyboard shortcuts"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Customise shortcuts"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Remove shortcut?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Reset back to default?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Press key to assign shortcut"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Key combination already in use. Try another key."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Shortcut cannot be set."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Add shortcut"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Delete shortcut"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigate using your keyboard"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Learn keyboards shortcuts"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigate using your touchpad"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 30eb21f9308f..f31e51f7f3da 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellite, good connection"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellite, connection available"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Emergency calls or SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"No signal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"one bar"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"enter device"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Ongoing call"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Temporarily connected"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Current app"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibility"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Keyboard shortcuts"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Customise keyboard shortcuts"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Customise shortcuts"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Remove shortcut?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Reset back to default?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Press key to assign shortcut"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Key combination already in use. Try another key."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Shortcut cannot be set."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Add shortcut"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Delete shortcut"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigate using your keyboard"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Learn keyboards shortcuts"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigate using your touchpad"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 2b3c54d9e280..dacea9ff1b61 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satélite, buena conexión"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, conexión disponible"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS por satélite"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Llamadas de emergencia o SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"sin señal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"una barra"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ingresar al dispositivo"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa la huella dactilar para abrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Se requiere de una autenticación. Toca el sensor de huellas dactilares para autenticarte."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Llamada en curso"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Datos móviles"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Conexión establecida"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Conectado temporalmente"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"App actual"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accesibilidad"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Combinaciones de teclas"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personaliza las combinaciones de teclas"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalizar combinaciones de teclas"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"¿Quieres quitar la combinación?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"¿Quieres restablecer la configuración predeterminada?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Presiona una tecla para asignar la combinación"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"La combinación de teclas ya está en uso. Prueba con otra."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"No se puede establecer la combinación de teclas."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Agregar combinación de teclas"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Borrar combinación de teclas"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navega con el teclado"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprende combinaciones de teclas"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navega con el panel táctil"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 69fab5ac89db..1799055627c1 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satélite, buena conexión"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, conexión disponible"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS por satélite"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Llamadas de emergencia o SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"no hay señal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"una barra"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"acceder al dispositivo"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa la huella digital para abrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticación obligatoria. Toca el sensor de huellas digitales para autenticarte."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Llamada en curso"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Datos móviles"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Conectado"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Conectada temporalmente"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aplicación en uso"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accesibilidad"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Combinaciones de teclas"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizar las combinaciones de teclas"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalizar combinaciones de teclas"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"¿Eliminar combinación de teclas?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"¿Restablecer valores predeterminados?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pulsa una tecla para asignar una combinación de teclas"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"La combinación de teclas ya se está usando. Prueba con otra tecla."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"No se puede configurar la combinación de teclas."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Añadir combinación de teclas"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Eliminar combinación de teclas"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Desplázate con el teclado"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprende combinaciones de teclas"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Desplázate con el panel táctil"</string>
@@ -1517,7 +1519,7 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Desliza hacia arriba con tres dedos y mantén pulsado. Toca para aprender a usar más gestos."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Usa el teclado para ver todas las aplicaciones"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Pulsa la tecla de acción en cualquier momento. Toca para aprender a usar más gestos."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"La atenuación extra ahora forma parte del control deslizante de brillo"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"La atenuación extra ahora forma parte del control deslizante de brillo"</string>
<string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Ahora puedes atenuar aún más tu pantalla reduciendo el nivel de brillo.\n\nComo esta función ahora forma parte del control deslizante de brillo, se van a quitar los accesos directos de atenuación extra."</string>
<string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Eliminar accesos directos de atenuación extra"</string>
<string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Accesos directos de atenuación extra eliminados"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 2ba50051b6ab..a91e3dcc7b2f 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelliit, hea ühendus"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelliit, ühendus on saadaval"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelliit-SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Hädaabikõned või SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"signaal puudub"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"üks pulk"</string>
@@ -814,7 +815,7 @@
<string name="notification_channel_controls_opened_accessibility" msgid="6111817750774381094">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> märguannete juhtelemendid on avatud"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="1561909368876911701">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> märguannete juhtelemendid on suletud"</string>
<string name="notification_more_settings" msgid="4936228656989201793">"Rohkem seadeid"</string>
- <string name="notification_app_settings" msgid="8963648463858039377">"Kohandamine"</string>
+ <string name="notification_app_settings" msgid="8963648463858039377">"Kohanda"</string>
<string name="notification_conversation_bubble" msgid="2242180995373949022">"Kuva mull"</string>
<string name="notification_conversation_unbubble" msgid="6908427185031099868">"Eemalda mullid"</string>
<string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"seadmesse sisenemiseks"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Kasutage avamiseks sõrmejälge"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Vajalik on autentimine. Puudutage autentimiseks sõrmejäljeandurit."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Käimasolev kõne"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiilne andmeside"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Ühendatud"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Ajutiselt ühendatud"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Praegune rakendus"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Juurdepääsetavus"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Klaviatuuri otseteed"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Klaviatuuri otseteede kohandamine"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Otseteede kohandamine"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Kas soovite otsetee eemaldada?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Kas lähtestada vaikeseadele?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Otsetee lisamiseks vajutage klahvi"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Kombinatsioon on juba kasutusel. Proovige mõnda muud klahvi."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Otseteed ei saa seadistada."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Otsetee lisamine"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Otsetee kustutamine"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigeerige klaviatuuri abil"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Õppige klaviatuuri otseteid"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigeerige puuteplaadi abil"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 89ec1dda2435..3a3c9cc144a6 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -228,7 +228,7 @@
<string name="fingerprint_re_enroll_dialog_title" msgid="3526033128113925780">"Konfiguratu hatz-marka bidez desblokeatzeko eginbidea"</string>
<string name="fingerprint_re_enroll_dialog_content" msgid="4866561176695984879">"Hatz-marka bidez desblokeatzeko eginbidea berriro konfiguratzeko, oraingo hatz-markaren irudiak eta ereduak ezabatu egingo dira lehendabizi.\n\nHaiek ezabatuz gero, hatz-marka bidez desblokeatzeko eginbidea berriro konfiguratu beharko duzu telefonoa hatz-marka erabilita desblokeatzeko edo zeu zarela egiaztatzeko."</string>
<string name="fingerprint_re_enroll_dialog_content_singular" msgid="3083663339787381218">"Hatz-marka bidez desblokeatzeko eginbidea berriro konfiguratzeko, oraingo hatz-markaren irudiak eta eredua ezabatu egingo dira lehendabizi.\n\nHaiek ezabatuz gero, hatz-marka bidez desblokeatzeko eginbidea berriro konfiguratu beharko duzu telefonoa hatz-marka erabilita desblokeatzeko edo zeu zarela egiaztatzeko."</string>
- <string name="fingerprint_reenroll_failure_dialog_content" msgid="4733768492747300666">"Ezin izan da konfiguratu hatz-marka bidez desblokeatzeko eginbidea. Berriro saiatzeko, joan ezarpenetara."</string>
+ <string name="fingerprint_reenroll_failure_dialog_content" msgid="4733768492747300666">"Ezin izan da konfiguratu hatz-marka bidez desblokeatzeko eginbidea. Berriro saiatzeko, joan Ezarpenak atalera."</string>
<string name="face_re_enroll_notification_title" msgid="1850838867718410520">"Konfiguratu berriro aurpegi bidez desblokeatzeko eginbidea"</string>
<string name="face_re_enroll_notification_name" msgid="7384545252206120659">"Aurpegi bidez desblokeatzea"</string>
<string name="face_re_enroll_dialog_title" msgid="6392173708176069994">"Konfiguratu aurpegi bidez desblokeatzeko eginbidea"</string>
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelitea, konexio ona"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelitea, konexioa erabilgarri"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelite bidezko SOS komunikazioa"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Larrialdi-deiak edo SOS komunikazioa"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"ez dago seinalerik"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"barra bat"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"sartu gailuan"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Erabili hatz-marka irekitzeko"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentifikazioa behar da. Autentifikatzeko, ukitu hatz-marken sentsorea."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Deia abian"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Datu-konexioa"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Konektatuta"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Aldi baterako konektatuta"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Oraingo aplikazioa"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Erabilerraztasuna"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Lasterbideak"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Pertsonalizatu lasterbideak"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Pertsonalizatu lasterbideak"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Lasterbidea kendu nahi duzu?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Balio lehenetsia berrezarri nahi duzu?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Sakatu tekla lasterbidea esleitzeko"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Tekla-konbinazio hori erabili da dagoeneko. Probatu beste tekla bat."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Ezin da ezarri lasterbidea."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Gehitu lasterbide bat"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Ezabatu lasterbidea"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Nabigatu teklatua erabilita"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Ikasi lasterbideak"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Nabigatu ukipen-panela erabilita"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index ae15b2ffe203..2caaf1415470 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ماهواره، اتصال خوب است"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ماهواره، اتصال دردسترس است"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"درخواست کمک ماهواره‌ای"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"تماس اضطراری یا درخواست کمک اضطراری"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"‫<xliff:g id="CARRIER_NAME">%1$s</xliff:g>، <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"سیگنال وجود ندارد"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"یک خط"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"وارد شدن به دستگاه"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"از اثر انگشت برای باز کردن قفل استفاده کنید"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"اصالت‌سنجی لازم است. برای اصالت‌سنجی، حسگر اثر انگشت را لمس کنید."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"تماس درحال انجام"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"داده تلفن همراه"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"متصل است"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"موقتاً متصل است"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"برنامه فعلی"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"دسترس‌پذیری"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"میان‌برهای صفحه‌کلید"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"سفارشی‌سازی کردن میان‌برهای صفحه‌کلید"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"سفارشی‌سازی میان‌برها"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"میان‌بر حذف شود؟"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"به تنظیم پیش‌فرض بازنشانی می‌کنید؟"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"برای اختصاص دادن میان‌بر، کلید را فشار دهید"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"ترکیب کلید ازقبل درحال استفاده است. کلید دیگری را امتحان کنید."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"میان‌بر تنظیم نشد."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"افزودن میان‌بر"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"حذف میان‌بر"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"پیمایش کردن بااستفاده از صفحه‌کلید"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"آشنایی با میان‌برهای صفحه‌کلید"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"پیمایش کردن بااستفاده از صفحه لمسی"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 3220bfcb8d65..0bd79100a959 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -761,7 +761,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelliitti, hyvä yhteys"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelliitti, yhteys saatavilla"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Hätäpuhelut tai Satellite SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"ei signaalia"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"yksi palkki"</string>
@@ -1291,8 +1292,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"avataksesi laitteen"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Avaa sormenjäljellä"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Todennus vaaditaan. Todenna koskettamalla sormenjälkitunnistinta."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Käynnissä oleva puhelu"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiilidata"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Yhdistetty"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Väliaikaisesti yhdistetty"</string>
@@ -1439,7 +1439,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Nykyinen sovellus"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Saavutettavuus"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Pikanäppäimet"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Pikanäppäimien muokkaaminen"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Muokkaa pikanäppäimiä"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Poistetaanko pikanäppäin?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Palautetaanko oletusasetukset?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Määritä pikanäppäin painamalla näppäintä"</string>
@@ -1467,6 +1467,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Näppäinyhdistelmä on jo käytössä. Kokeile toista näppäintä."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Pikakuvaketta ei voi lisätä."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Lisää pikanäppäin"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Poista pikanäppäin"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Siirry käyttämällä näppäimistöä"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Opettele pikanäppäimiä"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Siirry käyttämällä kosketuslevyä"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 367c7591a2b7..f93ceb498f4c 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Bonne connexion satellite"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Connexion satellite accessible"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS par satellite"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Appels d\'urgence ou SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"aucun signal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"une barre"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"accéder à l\'appareil"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Servez-vous de votre empreinte digitale pour ouvrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentification requise. Touchez le capteur d\'empreintes digitales pour vous authentifier."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Appel en cours"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Données cellulaires"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connexion active"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Connectée temporairement"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Appli actuelle"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibilité"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Raccourcis-clavier"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personnaliser les raccourcis-clavier"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personnaliser les raccourcis"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Supprimer le raccourci?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Réinitialiser aux raccourcis par défaut?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Appuyez sur la touche pour attribuer un raccourci"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"La combinaison de touches est déjà utilisée. Essayez une autre touche."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Le raccourci ne peut pas être défini."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Ajouter un raccourci"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Supprimer le raccourci"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviguer à l\'aide de votre clavier"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Apprenez à utiliser les raccourcis-clavier"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviguer à l\'aide de votre pavé tactile"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index dc10bcbf74be..f0cc3b52fa02 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Bonne connexion satellite"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Connexion satellite disponible"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS par satellite"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Appels d\'urgence ou SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"aucun signal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"faible"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"accéder à l\'appareil"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Utilisez votre empreinte pour ouvrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentification requise. Appuyez sur le lecteur d\'empreintes digitales pour vous authentifier."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Appel en cours"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Données mobiles"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connecté"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Connexion temporaire"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Appli actuelle"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibilité"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Raccourcis clavier"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personnaliser les raccourcis clavier"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personnaliser les raccourcis"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Supprimer le raccourci ?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Rétablir les paramètres par défaut ?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Appuyez sur une touche pour attribuer un raccourci"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Combinaison de touches déjà utilisée. Essayez une autre touche."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Impossible de définir le raccourci."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Ajouter un raccourci"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Supprimer le raccourci"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviguer à l\'aide du clavier"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Apprenez à utiliser les raccourcis clavier"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviguer à l\'aide de votre pavé tactile"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index eef9147bbfab..a449530050e5 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satélite, boa conexión"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, conexión dispoñible"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS por satélite"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Chamadas de emerxencia ou SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"non hai cobertura"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"unha barra"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"poñer o dispositivo"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa a impresión dixital para abrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Requírese autenticación. Para autenticarte, toca o sensor de impresión dixital."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Chamada en curso"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Datos móbiles"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Conectada"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Conectada temporalmente"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aplicación actual"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accesibilidade"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Atallos de teclado"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizar os atallos de teclado"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalizar os atallos"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Queres quitar o atallo?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Queres restablecer a opción predeterminada?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Preme a tecla para asignar o atallo"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Xa se está usando esta combinación de teclas. Proba con outra."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Non se puido definir o atallo."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Engadir un atallo"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Eliminar un atallo"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navega co teclado"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprende a usar os atallos de teclado"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navega co panel táctil"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 88b4f34c90c3..727d11248e8c 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"સૅટલાઇટ, સારું કનેક્શન"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"સૅટલાઇટ, કનેક્શન ઉપલબ્ધ છે"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"ઇમર્જન્સી સૅટલાઇટ સહાય"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"ઇમર્જન્સી કૉલ અથવા SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"કોઈ સિગ્નલ નથી"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"એક બાર"</string>
@@ -843,7 +844,7 @@
<string name="keyboard_key_page_up" msgid="173914303254199845">"Page Up"</string>
<string name="keyboard_key_page_down" msgid="9035902490071829731">"Page Down"</string>
<string name="keyboard_key_forward_del" msgid="5325501825762733459">"Delete"</string>
- <string name="keyboard_key_esc" msgid="6230365950511411322">"Esc કી"</string>
+ <string name="keyboard_key_esc" msgid="6230365950511411322">"Esc"</string>
<string name="keyboard_key_move_home" msgid="3496502501803911971">"Home"</string>
<string name="keyboard_key_move_end" msgid="99190401463834854">"End"</string>
<string name="keyboard_key_insert" msgid="4621692715704410493">"Insert"</string>
@@ -881,7 +882,7 @@
<string name="group_system_cycle_back" msgid="8194102916946802902">"તાજેતરની ઍપ પર પાછળ જાઓ"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"ઍપની સૂચિ ખોલો"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"સેટિંગ ખોલો"</string>
- <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant ખોલો"</string>
+ <string name="group_system_access_google_assistant" msgid="7210074957915968110">"આસિસ્ટંટ ખોલો"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"લૉક સ્ક્રીન"</string>
<string name="group_system_quick_memo" msgid="3764560265935722903">"નોંધ લો"</string>
<string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"એકસાથે એકથી વધુ કાર્યો કરવા"</string>
@@ -1069,7 +1070,7 @@
<string name="privacy_type_media_projection" msgid="8136723828804251547">"સ્ક્રીન રેકોર્ડિંગ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"કોઈ શીર્ષક નથી"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"સ્ટૅન્ડબાય"</string>
- <string name="font_scaling_dialog_title" msgid="6273107303850248375">"ફૉન્ટનું કદ"</string>
+ <string name="font_scaling_dialog_title" msgid="6273107303850248375">"ફૉન્ટ સાઇઝ"</string>
<string name="font_scaling_smaller" msgid="1012032217622008232">"વધુ નાનું બનાવો"</string>
<string name="font_scaling_larger" msgid="5476242157436806760">"વધુ મોટું બનાવો"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"વિસ્તૃતીકરણ વિંડો"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ડિવાઇસ અનલૉક કરો"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ખોલવા માટે ફિંગરપ્રિન્ટનો ઉપયોગ કરો"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"પ્રમાણીકરણ આવશ્યક છે. પ્રમાણિત કરવા માટે ફિંગરપ્રિન્ટ સેન્સરને ટચ કરો."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"ચાલુ કૉલ"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"મોબાઇલ ડેટા"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"કનેક્ટ કરેલું"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"હંગામી રીતે કનેક્ટ કર્યું"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"હાલની ઍપ"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ઍક્સેસિબિલિટી"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"કીબોર્ડ શૉર્ટકટ"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"કીબોર્ડ શૉર્ટકટને કસ્ટમાઇઝ કરો"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"શૉર્ટકટ કસ્ટમાઇઝ કરો"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"શું શૉર્ટકટ કાઢી નાખીએ?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"પાછા ડિફૉલ્ટ પર રીસેટ કરીએ?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"શૉર્ટકટ સોંપવા માટે કી દબાવો"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"કી સંયોજન પહેલેલેથી ઉપયોગમાં છે. અન્ય કી અજમાવી જુઓ."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"શૉર્ટકટ સેટ કરી શકાતો નથી."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"શૉર્ટકટ ઉમેરો"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"શૉર્ટકટ ડિલીટ કરો"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"તમારા કીબોર્ડ વડે નૅવિગેટ કરો"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"કીબોર્ડ શૉર્ટકર્ટ જાણો"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"તમારા ટચપૅડ વડે નૅવિગેટ કરો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 1f7066e0d663..f58512db0863 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"सैटलाइट कनेक्शन अच्छा है"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"सैटलाइट कनेक्शन उपलब्ध है"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"सैटलाइट एसओएस"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"आपातकालीन कॉल या एसओएस"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"सिग्नल नहीं है"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"एक सिग्नल बार"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"डिवाइस की होम स्क्रीन पर जाएं"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"खोलने के लिए, फ़िंगरप्रिंट का इस्तेमाल करें"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"पुष्टि करना ज़रूरी है. पुष्टि करने के लिए, फ़िंगरप्रिंट सेंसर को छुएं."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"पहले से जारी कॉल"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"मोबाइल डेटा"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"कनेक्ट हो गया"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"इंटरनेट कनेक्शन कुछ समय के लिए है"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"मौजूदा ऐप्लिकेशन"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"सुलभता"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"कीबोर्ड शॉर्टकट"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"कीबोर्ड शॉर्टकट को पसंद के मुताबिक बनाएं"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"पसंद के मुताबिक शॉर्टकट बनाएं"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"क्या आपको शॉर्टकट हटाना है?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"क्या आपको फिर से डिफ़ॉल्ट सेटिंग चालू करनी है?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"शॉर्टकट असाइन करने के लिए बटन दबाएं"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"बटन का यह कॉम्बिनेशन पहले से इस्तेमाल किया जा रहा है. कोई दूसरा कॉम्बिनेशन आज़माएं."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"शॉर्टकट सेट नहीं किया जा सकता."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"शॉर्टकट जोड़ें"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"शॉर्टकट मिटाएं"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"कीबोर्ड का इस्तेमाल करके नेविगेट करें"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"कीबोर्ड शॉर्टकट के बारे में जानें"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"टचपैड का इस्तेमाल करके नेविगेट करें"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 5c40a5170fa7..b8b5f82dbf71 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, dobra veza"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, veza je dostupna"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS putem satelita"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Hitni pozivi ili SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"nema signala"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"jedna crtica"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"pristupili uređaju"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorite pomoću otiska prsta"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Potrebna je autentifikacija. Dodirnite senzor otiska prsta da biste se autentificirali."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Poziv u tijeku"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilni podaci"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Privremeno povezano"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Trenutačna aplikacija"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Pristupačnost"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Tipkovni prečaci"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prilagodba tipkovnih prečaca"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Prilagodite prečace"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Želite li ukloniti prečac?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Želite li vratiti na zadano?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pritisnite tipku da biste dodijelili prečac"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Ta se kombinacija već koristi. Pokušajte s nekom drugom."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Prečac se ne može postaviti."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Dodaj prečac"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Izbriši prečac"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Krećite se pomoću tipkovnice"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Saznajte više o tipkovnim prečacima"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Krećite se pomoću dodirne podloge"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 50c60833574a..e914e755a934 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Műhold, jó kapcsolat"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Műhold, van rendelkezésre álló kapcsolat"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Műholdas SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Segélyhívás vagy SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"nincs jel"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"egy sáv"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"eszköz megadásához"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Ujjlenyomat használata a megnyitáshoz"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Hitelesítés szükséges. Érintse meg az ujjlenyomat-érzékelőt a hitelesítéshez."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Hívás folyamatban"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiladat"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Csatlakozva"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Ideiglenesen csatlakoztatva"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Jelenlegi alkalmazás"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Kisegítő lehetőségek"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Billentyűparancsok"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"A billentyűparancsok személyre szabása"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Gyorsparancsok személyre szabása"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Eltávolítja a billentyűparancsot?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Visszaállítja az alapértelmezett beállításokat?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Nyomja meg a billentyűt a billentyűparancs hozzárendeléséhez"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"A billentyűkombináció már használatban van. Próbálkozzon másik billentyűvel."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Nem lehet beállítani a billentyűparancsot."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Billentyűparancs hozzáadása"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Billentyűparancs törlése"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigáció a billentyűzet segítségével"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Billentyűparancsok megismerése"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigálás az érintőpaddal"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 2e42ecd6a25f..262c3dd93cdd 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Արբանյակային լավ կապ"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Հասանելի է արբանյակային կապ"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Շտապ կանչեր կամ SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>։"</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"ազդանշան չկա"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"մեկ գիծ"</string>
@@ -884,7 +885,7 @@
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Բացել Օգնականը"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Կողպէկրան"</string>
<string name="group_system_quick_memo" msgid="3764560265935722903">"Ստեղծել նշում"</string>
- <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Բազմախնդրու­թյուն"</string>
+ <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Բազմա­խնդրու­թ­յուն"</string>
<string name="system_multitasking_rhs" msgid="8779289852395243004">"Տրոհել էկրանը և տեղավորել այս հավելվածը աջ կողմում"</string>
<string name="system_multitasking_lhs" msgid="7348595296208696452">"Տրոհել էկրանը և տեղավորել այս հավելվածը ձախ կողմում"</string>
<string name="system_multitasking_full_screen" msgid="4940465971687159429">"Անցնել լիաէկրան ռեժիմի"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"նշել սարքը"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Բացելու համար օգտագործեք մատնահետքը"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Պահանջվում է նույնականացում։ Դրա համար մատը հպեք մատնահետքի սկաներին։"</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Ընթացիկ զանգ"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Բջջային ինտերնետ"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Միացած է"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Ժամանակավոր կապ"</string>
@@ -1430,14 +1430,14 @@
<string name="shortcut_helper_category_system" msgid="462110876978937359">"Համակարգ"</string>
<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>
+ <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Բազմա­խնդրու­թ­յուն"</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_current_app_shortcuts" msgid="4017840565974573628">"Այս հավելվածը"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Հատուկ գործառույթներ"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Ստեղնային դյուրանցումներ"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Կարգավորեք ստեղնային դյուրանցումներ"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Դյուրանցումների անհատականացում"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Հեռացնե՞լ դյուրանցումը"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Վերականգնե՞լ կանխադրվածները"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Սեղմեք որևէ ստեղն՝ դյուրանցում նշանակելու համար"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Ստեղների համակցությունն արդեն օգտագործվում է։ Ընտրեք ուրիշը։"</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Դյուրանցումը հնարավոր չէ ստեղծել։"</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Ավելացնել դյուրանցում"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Ջնջել դյուրանցումը"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Կողմնորոշվեք ձեր ստեղնաշարի օգնությամբ"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Սովորեք օգտագործել ստեղնային դյուրանցումները"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Կողմնորոշվեք ձեր հպահարթակի օգնությամբ"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 2740ce508515..8e1118c76e24 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, koneksi baik"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, koneksi tersedia"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via Satelit"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Panggilan darurat atau SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"tidak ada sinyal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"satu batang"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"masukkan perangkat"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gunakan sidik jari untuk membuka"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Perlu autentikasi. Sentuh sensor sidik jari untuk melakukan autentikasi."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Panggilan sedang berlangsung"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Data seluler"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Terhubung"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Terhubung sementara"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aplikasi Saat Ini"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Aksesibilitas"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Pintasan keyboard"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Sesuaikan pintasan keyboard"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Sesuaikan pintasan"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Hapus pintasan?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Reset kembali ke pintasan default?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Tekan tombol untuk menetapkan pintasan"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Kombinasi tombol sudah digunakan. Coba tombol lain."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Pintasan tidak dapat disetel."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Tambahkan pintasan"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Hapus pintasan"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Menggunakan keyboard untuk navigasi"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Pelajari pintasan keyboard"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Menavigasi menggunakan touchpad"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index a6de1d70805e..f5488e0939de 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Gervihnöttur, góð tenging"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Gervihnöttur, tenging tiltæk"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Gervihnattar-SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Neyðarsímtöl eða SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"ekkert samband"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"eitt strik"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"opna tæki"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Opna með fingrafari"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Auðkenningar krafist. Auðkenndu með því að snerta fingrafaralesarann."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Símtal í gangi"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Farsímagögn"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Tengt"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Tímabundin tenging"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Núverandi forrit"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Aðgengi"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Flýtilyklar"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Sérsníddu flýtilykla"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Sérsníða flýtilykla"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Fjarlægja flýtileið?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Endurstilla á sjálfgefið?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Ýttu á lykil til að stilla flýtileið"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Lyklasamsetningin er þegar í notkun. Prófaðu annan lykil."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Ekki er hægt að stilla flýtileið."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Bæta flýtileið við"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Eyða flýtileið"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Flettu með því að nota lyklaborðið"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Kynntu þér flýtilykla"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Flettu með því að nota snertiflötinn"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 86aeae467b91..81367f369159 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellitare, connessione buona"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellitare, connessione disponibile"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS satellitare"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Chiamate di emergenza o SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"nessun segnale"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"una barra"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"accedere al dispositivo"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa l\'impronta per aprire"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticazione obbligatoria. Eseguila toccando il sensore di impronte digitali."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Chiamata in corso"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Dati mobili"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connessa"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Connessa temporaneamente"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"App corrente"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibilità"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Scorciatoie da tastiera"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizza scorciatoie da tastiera"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalizza scorciatoie"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Rimuovere scorciatoia?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Vuoi ripristinare le impostazioni predefinite?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Premi un tasto per assegnare una scorciatoia"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Combinazione di tasti già in uso. Prova con un altro tasto."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Impossibile impostare la scorciatoia."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Aggiungi scorciatoia"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Elimina scorciatoia"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviga usando la tastiera"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Informazioni sulle scorciatoie da tastiera"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviga usando il touchpad"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 605a1fb88cc3..a40dd62c4620 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -129,7 +129,7 @@
<string name="screenrecord_stop_label" msgid="72699670052087989">"עצירה"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"שיתוף"</string>
<string name="screenrecord_save_title" msgid="1886652605520893850">"הקלטת המסך נשמרה"</string>
- <string name="screenrecord_save_text" msgid="3008973099800840163">"יש להקיש כדי להציג"</string>
+ <string name="screenrecord_save_text" msgid="3008973099800840163">"יש ללחוץ כדי להציג"</string>
<string name="screenrecord_save_error" msgid="5862648532560118815">"שגיאה בשמירה של הקלטת המסך"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"שגיאה בהפעלה של הקלטת המסך"</string>
<string name="screenrecord_stop_dialog_title" msgid="8716193661764511095">"לעצור את ההקלטה?"</string>
@@ -162,7 +162,7 @@
<string name="issuerecord_ongoing_screen_only" msgid="6248206059935015722">"הבעיה בתהליך הקלטה"</string>
<string name="issuerecord_share_label" msgid="3992657993619876199">"שיתוף"</string>
<string name="issuerecord_save_title" msgid="4161043023696751591">"הקלטת הבעיה נשמרה"</string>
- <string name="issuerecord_save_text" msgid="1205985304551521495">"אפשר להקיש כדי להציג"</string>
+ <string name="issuerecord_save_text" msgid="1205985304551521495">"אפשר ללחוץ כדי להציג"</string>
<string name="issuerecord_save_error" msgid="6913040083446722726">"שגיאה בשמירה של בעיית ההקלטה"</string>
<string name="issuerecord_start_error" msgid="3402782952722871190">"שגיאה בהפעלה של בעיית ההקלטה"</string>
<string name="immersive_cling_title" msgid="8372056499315585941">"צפייה במסך מלא"</string>
@@ -187,17 +187,17 @@
<string name="biometric_dialog_logo" msgid="7681107853070774595">"לוגו של האפליקציה"</string>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"אישור"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"ניסיון נוסף"</string>
- <string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"יש להקיש כדי לבטל את האימות"</string>
+ <string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"יש ללחוץ כדי לבטל את האימות"</string>
<string name="biometric_dialog_face_icon_description_idle" msgid="4351777022315116816">"יש לנסות שוב"</string>
<string name="biometric_dialog_face_icon_description_authenticating" msgid="3401633342366146535">"המערכת מחפשת את הפנים שלך"</string>
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"זיהוי הפנים בוצע"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"יש אישור"</string>
- <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"יש להקיש על \'אישור\' לסיום התהליך"</string>
+ <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"יש ללחוץ על \'אישור\' לסיום התהליך"</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"הנעילה בוטלה באמצעות זיהוי הפנים"</string>
<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>
- <string name="biometric_dialog_tap_confirm_with_face_sfps" msgid="2499213248903257928">"הנעילה בוטלה באמצעות זיהוי הפנים. צריך להקיש כדי להמשיך."</string>
+ <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>
@@ -300,7 +300,7 @@
<string name="quick_settings_modes_label" msgid="879156359479504244">"מצבים"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"אין מכשירים מותאמים זמינים"</string>
- <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"אפשר להקיש כדי להתחבר למכשיר או להתנתק ממנו"</string>
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"אפשר ללחוץ כדי להתחבר למכשיר או להתנתק ממנו"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"התאמה של מכשיר חדש"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"הצגת הכול"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"‏שימוש ב-Bluetooth"</string>
@@ -449,7 +449,7 @@
<string name="sensor_privacy_camera_turned_off_dialog_title" msgid="1936603903120742696">"המצלמה כבויה"</string>
<string name="sensor_privacy_camera_unblocked_dialog_content" msgid="7847190103011782278">"הגישה למצלמה הופעלה לכל האפליקציות והשירותים."</string>
<string name="sensor_privacy_camera_blocked_dialog_content" msgid="3182428709314874616">"הגישה למצלמה הושבתה לכל האפליקציות והשירותים."</string>
- <string name="sensor_privacy_htt_blocked_dialog_content" msgid="3333321592997666441">"כדי להשתמש בלחצן המיקרופון יש להפעיל את הגישה למיקרופון ב\'הגדרות\'."</string>
+ <string name="sensor_privacy_htt_blocked_dialog_content" msgid="3333321592997666441">"כדי להשתמש בכפתור המיקרופון יש להפעיל את הגישה למיקרופון ב\'הגדרות\'."</string>
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"פתיחת ההגדרות"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"מכשיר אחר"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"החלפת מצב של מסכים אחרונים"</string>
@@ -467,8 +467,8 @@
<string name="zen_priority_customize_button" msgid="4119213187257195047">"התאמה אישית"</string>
<string name="zen_silence_introduction_voice" msgid="853573681302712348">"הפעולה הזו מבטלת את כל הצלילים והרטט, כולל צלילים ורטט שמקורם בהתראות, מוזיקה, סרטונים ומשחקים. עדיין ניתן לבצע שיחות."</string>
<string name="zen_silence_introduction" msgid="6117517737057344014">"הפעולה הזו מבטלת את כל הצלילים והרטט, כולל בהתראות, מוזיקה, סרטונים ומשחקים."</string>
- <string name="notification_tap_again" msgid="4477318164947497249">"יש להקיש שוב כדי לפתוח את ההתראה"</string>
- <string name="tap_again" msgid="1315420114387908655">"צריך להקיש פעם נוספת"</string>
+ <string name="notification_tap_again" msgid="4477318164947497249">"יש ללחוץ שוב כדי לפתוח את ההתראה"</string>
+ <string name="tap_again" msgid="1315420114387908655">"צריך ללחוץ פעם נוספת"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"צריך להחליק כדי לפתוח"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"לפתיחה, לוחצים על סמל ביטול הנעילה"</string>
<string name="keyguard_face_successful_unlock_swipe" msgid="6180997591385846073">"הנעילה בוטלה באמצעות זיהוי הפנים. צריך להחליק כדי לפתוח."</string>
@@ -538,7 +538,7 @@
<string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ווידג\'טים"</string>
<string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"כדי להוסיף את קיצור הדרך \"ווידג\'טים\", צריך לוודא שהאפשרות \"ווידג\'טים במסך הנעילה\" מופעלת בהגדרות."</string>
<string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"הגדרות"</string>
- <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"לחצן להצגת שומר המסך"</string>
+ <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"כפתור להצגת שומר המסך"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"החלפת משתמש"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"תפריט במשיכה למטה"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"כל האפליקציות והנתונים בסשן הזה יימחקו."</string>
@@ -677,8 +677,8 @@
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצן \'דף הבית\' כדי לבטל את ההצמדה."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ייתכן שתתאפשר גישה למידע אישי (כמו אנשי קשר ותוכן מהאימייל)."</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"האפליקציה שהוצמדה עשויה לפתוח אפליקציות אחרות."</string>
- <string name="screen_pinning_toast" msgid="8177286912533744328">"כדי לבטל את ההצמדה של האפליקציה הזו, יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'סקירה\'"</string>
- <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"כדי לבטל את ההצמדה של האפליקציה הזו, יש ללחוץ לחיצה ארוכה על הלחצן \'הקודם\' והלחצן הראשי"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"כדי לבטל את ההצמדה של האפליקציה הזו, יש ללחוץ לחיצה ארוכה על הכפתורים \"הקודם\" ו\"סקירה\""</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"כדי לבטל את ההצמדה של האפליקציה הזו, יש ללחוץ לחיצה ארוכה על הכפתור \"הקודם\" והכפתור הראשי"</string>
<string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"לביטול ההצמדה של האפליקציה הזו, יש להחליק למעלה ולהחזיק"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"הבנתי"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"לא, תודה"</string>
@@ -702,19 +702,19 @@
<string name="stream_media_unavailable" msgid="6823020894438959853">"לא זמין כי התכונה \'נא לא להפריע\' מופעלת"</string>
<string name="stream_unavailable_by_modes" msgid="3674139029490353683">"לא זמין כי המצב <xliff:g id="MODE">%s</xliff:g> מופעל"</string>
<string name="stream_unavailable_by_unknown" msgid="6908434629318171588">"לא זמין"</string>
- <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"‏%1$s. יש להקיש כדי לבטל את ההשתקה."</string>
- <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"‏%1$s. צריך להקיש כדי להגדיר רטט. ייתכן ששירותי הנגישות מושתקים."</string>
- <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‏%1$s. יש להקיש כדי להשתיק. ייתכן ששירותי הנגישות יושתקו."</string>
- <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"‏%1$s. יש להקיש כדי להעביר למצב רטט."</string>
- <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"‏%1$s. יש להקיש כדי להשתיק."</string>
+ <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"‏%1$s. יש ללחוץ כדי לבטל את ההשתקה."</string>
+ <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"‏%1$s. צריך ללחוץ כדי להגדיר רטט. ייתכן ששירותי הנגישות מושתקים."</string>
+ <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‏%1$s. יש ללחוץ כדי להשתיק. ייתכן ששירותי הנגישות יושתקו."</string>
+ <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"‏%1$s. יש ללחוץ כדי להעביר למצב רטט."</string>
+ <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"‏%1$s. יש ללחוץ כדי להשתיק."</string>
<string name="volume_panel_noise_control_title" msgid="7413949943872304474">"בקרת רעש"</string>
<string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"אודיו מרחבי"</string>
<string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"השבתה"</string>
<string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"מצב סטטי"</string>
<string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"מעקב ראש"</string>
- <string name="volume_ringer_change" msgid="3574969197796055532">"יש להקיש כדי לשנות את מצב תוכנת הצלצול"</string>
+ <string name="volume_ringer_change" msgid="3574969197796055532">"יש ללחוץ כדי לשנות את מצב תוכנת הצלצול"</string>
<string name="volume_ringer_mode" msgid="6867838048430807128">"מצב תוכנת הצלצול"</string>
- <string name="volume_ringer_drawer_closed_content_description" msgid="4737792429808781745">"<xliff:g id="VOLUME_RINGER_STATUS">%1$s</xliff:g>, צריך להקיש כדי לשנות את מצב תוכנת הצלצול"</string>
+ <string name="volume_ringer_drawer_closed_content_description" msgid="4737792429808781745">"<xliff:g id="VOLUME_RINGER_STATUS">%1$s</xliff:g>, צריך ללחוץ כדי לשנות את מצב תוכנת הצלצול"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"השתקה"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ביטול ההשתקה"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"רטט"</string>
@@ -736,12 +736,12 @@
<string name="enable_demo_mode" msgid="3180345364745966431">"הפעלת מצב הדגמה"</string>
<string name="show_demo_mode" msgid="3677956462273059726">"הצגת מצב הדגמה"</string>
<string name="status_bar_ethernet" msgid="5690979758988647484">"אתרנט"</string>
- <string name="status_bar_alarm" msgid="87160847643623352">"התראה"</string>
+ <string name="status_bar_alarm" msgid="87160847643623352">"שעון מעורר"</string>
<string name="active_mode_content_description" msgid="1627555562186515927">"מצב <xliff:g id="MODENAME">%1$s</xliff:g> פועל"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"מגדירים אמצעי תשלום ונהנים מביצוע מהיר ומאובטח יותר של רכישות באמצעות הטלפון"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"הצגת הכול"</string>
- <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"יש להקיש לפתיחה"</string>
+ <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"יש ללחוץ לפתיחה"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"מתבצע עדכון"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"יש לבטל את הנעילה כדי להשתמש"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"הייתה בעיה בקבלת הכרטיסים שלך. כדאי לנסות שוב מאוחר יותר"</string>
@@ -750,7 +750,7 @@
<string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"מתבצע עדכון"</string>
<string name="status_bar_work" msgid="5238641949837091056">"פרופיל עבודה"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"מצב טיסה"</string>
- <string name="zen_alarm_warning" msgid="7844303238486849503">"לא ניתן יהיה לשמוע את ההתראה הבאה שלך <xliff:g id="WHEN">%1$s</xliff:g>"</string>
+ <string name="zen_alarm_warning" msgid="7844303238486849503">"לא ניתן יהיה לשמוע את השעון המעורר הבא שלך <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"בשעה <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"ב-<xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"‏נקודת אינטרנט (hotspot)"</string>
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"לוויין, חיבור באיכות טובה"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"לוויין, יש חיבור זמין"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"תקשורת לוויינית למצב חירום"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"‏שיחות חירום או SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"‫<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"אין קליטה"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"פס אחד"</string>
@@ -827,7 +828,7 @@
<string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{שעה}=2{שעתיים}one{# שעות}other{# שעות}}"</string>
<string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{דקה}one{# דקות}two{# דקות}other{# דקות}}"</string>
<string name="battery_detail_switch_title" msgid="6940976502957380405">"חיסכון בסוללה"</string>
- <string name="keyboard_key_button_template" msgid="8005673627272051429">"לחצן <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="keyboard_key_button_template" msgid="8005673627272051429">"כפתור <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="3734400625170020657">"דף הבית"</string>
<string name="keyboard_key_back" msgid="4185420465469481999">"הקודם"</string>
<string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string>
@@ -871,9 +872,9 @@
<string name="keyboard_shortcut_a11y_filter_input" msgid="4589316004510335529">"מוצגים: קיצורי הדרך של הקלט"</string>
<string name="keyboard_shortcut_a11y_filter_open_apps" msgid="6175417687221004059">"מוצגים: קיצורי הדרך לפתיחת אפליקציות"</string>
<string name="keyboard_shortcut_a11y_filter_current_app" msgid="7944592357493737911">"מוצגים: קיצורי הדרך של האפליקציה הנוכחית"</string>
- <string name="group_system_access_notification_shade" msgid="1619028907006553677">"הצגת התראות"</string>
+ <string name="group_system_access_notification_shade" msgid="1619028907006553677">"צפייה בהתראות"</string>
<string name="group_system_full_screenshot" msgid="5742204844232667785">"צילום המסך"</string>
- <string name="group_system_access_system_app_shortcuts" msgid="8562482996626694026">"הצגת מקשי הקיצור"</string>
+ <string name="group_system_access_system_app_shortcuts" msgid="8562482996626694026">"צפייה במקשי הקיצור"</string>
<string name="group_system_go_back" msgid="2730322046244918816">"חזרה"</string>
<string name="group_system_access_home_screen" msgid="4130366993484706483">"מעבר למסך הבית"</string>
<string name="group_system_overview_open_apps" msgid="5659958952937994104">"צפייה באפליקציות האחרונות"</string>
@@ -912,7 +913,7 @@
<string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"מחשבון"</string>
<string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"מפות"</string>
<string name="volume_and_do_not_disturb" msgid="502044092739382832">"נא לא להפריע"</string>
- <string name="volume_dnd_silent" msgid="4154597281458298093">"קיצור דרך ללחצני עוצמת קול"</string>
+ <string name="volume_dnd_silent" msgid="4154597281458298093">"קיצור דרך לכפתורי עוצמת קול"</string>
<string name="battery" msgid="769686279459897127">"סוללה"</string>
<string name="headset" msgid="4485892374984466437">"אוזניות"</string>
<string name="accessibility_long_click_tile" msgid="210472753156768705">"פתיחת ההגדרות"</string>
@@ -926,8 +927,8 @@
<string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"מידע נוסף"</string>
<string name="nav_bar" msgid="4642708685386136807">"סרגל הניווט"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"פריסה"</string>
- <string name="left_nav_bar_button_type" msgid="2634852842345192790">"סוג נוסף של לחצן שמאלי"</string>
- <string name="right_nav_bar_button_type" msgid="4472566498647364715">"סוג נוסף של לחצן ימני"</string>
+ <string name="left_nav_bar_button_type" msgid="2634852842345192790">"סוג נוסף של כפתור שמאלי"</string>
+ <string name="right_nav_bar_button_type" msgid="4472566498647364715">"סוג נוסף של כפתור ימני"</string>
<string-array name="nav_bar_buttons">
<item msgid="2681220472659720036">"לוח"</item>
<item msgid="4795049793625565683">"קוד מפתח"</item>
@@ -943,7 +944,7 @@
<string name="save" msgid="3392754183673848006">"שמירה"</string>
<string name="reset" msgid="8715144064608810383">"איפוס"</string>
<string name="clipboard" msgid="8517342737534284617">"לוח"</string>
- <string name="accessibility_key" msgid="3471162841552818281">"לחצן לניווט מותאם אישית"</string>
+ <string name="accessibility_key" msgid="3471162841552818281">"כפתור לניווט מותאם אישית"</string>
<string name="left_keycode" msgid="8211040899126637342">"קוד מפתח שמאלי"</string>
<string name="right_keycode" msgid="2480715509844798438">"קוד מפתח ימני"</string>
<string name="left_icon" msgid="5036278531966897006">"סמל שמאלי"</string>
@@ -1020,7 +1021,7 @@
<string name="instant_apps" msgid="8337185853050247304">"אפליקציות ללא התקנה"</string>
<string name="instant_apps_title" msgid="8942706782103036910">"האפליקציה <xliff:g id="APP">%1$s</xliff:g> פועלת"</string>
<string name="instant_apps_message" msgid="6112428971833011754">"האפליקציה נפתחת בלי התקנה."</string>
- <string name="instant_apps_message_with_help" msgid="1816952263531203932">"האפליקציה נפתחת בלי התקנה. אפשר להקיש כדי לקבל מידע נוסף."</string>
+ <string name="instant_apps_message_with_help" msgid="1816952263531203932">"האפליקציה נפתחת בלי התקנה. אפשר ללחוץ כדי לקבל מידע נוסף."</string>
<string name="app_info" msgid="5153758994129963243">"פרטי האפליקציה"</string>
<string name="go_to_web" msgid="636673528981366511">"מעבר אל הדפדפן"</string>
<string name="mobile_data" msgid="4564407557775397216">"חבילת גלישה"</string>
@@ -1034,7 +1035,7 @@
<string name="qs_dnd_prompt_app" msgid="4027984447935396820">"מצב \'נא לא להפריע\' הופעל על ידי אפליקציה (<xliff:g id="ID_1">%s</xliff:g>)."</string>
<string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"מצב \'נא לא להפריע\' הופעל על ידי אפליקציה או על ידי כלל אוטומטי."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"אפליקציות שפועלות ברקע"</string>
- <string name="running_foreground_services_msg" msgid="3009459259222695385">"אפשר להקיש לקבלת פרטים על צריכה של נתונים וסוללה"</string>
+ <string name="running_foreground_services_msg" msgid="3009459259222695385">"אפשר ללחוץ לקבלת פרטים על צריכה של נתונים וסוללה"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"לכבות את השימוש בחבילת הגלישה?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"‏לא תהיה לך גישה לנתונים או לאינטרנט דרך <xliff:g id="CARRIER">%s</xliff:g>. אפשר יהיה לגשת לאינטרנט רק דרך Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"הספק שלך"</string>
@@ -1049,7 +1050,7 @@
<string name="slice_permission_checkbox" msgid="4242888137592298523">"יש לאשר לאפליקציית <xliff:g id="APP">%1$s</xliff:g> להראות חלקים מכל אפליציה שהיא"</string>
<string name="slice_permission_allow" msgid="6340449521277951123">"אישור"</string>
<string name="slice_permission_deny" msgid="6870256451658176895">"אני לא מרשה"</string>
- <string name="auto_saver_title" msgid="6873691178754086596">"יש להקיש כדי לתזמן את מצב החיסכון בסוללה"</string>
+ <string name="auto_saver_title" msgid="6873691178754086596">"יש ללחוץ כדי לתזמן את מצב החיסכון בסוללה"</string>
<string name="auto_saver_text" msgid="3214960308353838764">"מומלץ להפעיל את התכונה כשיש סבירות גבוהה שהסוללה תתרוקן"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"לא תודה"</string>
<string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"בשימוש"</string>
@@ -1109,11 +1110,11 @@
<string name="accessibility_magnification_done" msgid="263349129937348512">"סיום"</string>
<string name="accessibility_magnifier_edit" msgid="1522877239671820636">"עריכה"</string>
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"ההגדרות של חלון ההגדלה"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"מקישים כדי לפתוח את תכונות הנגישות. אפשר להחליף את הלחצן או להתאים אותו אישית בהגדרות.\n\n"<annotation id="link">"הצגת ההגדרות"</annotation></string>
- <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"כדי להסתיר זמנית את הלחצן, יש להזיז אותו לקצה"</string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"לוחצים כדי לפתוח את תכונות הנגישות. אפשר להחליף את הכפתור או להתאים אותו אישית בהגדרות.\n\n"<annotation id="link">"הצגת ההגדרות"</annotation></string>
+ <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"כדי להסתיר זמנית את הכפתור, יש להזיז אותו לקצה"</string>
<string name="accessibility_floating_button_undo" msgid="511112888715708241">"ביטול"</string>
- <string name="accessibility_floating_button_hidden_notification_title" msgid="4115036997406994799">"לחצן הנגישות מוסתר"</string>
- <string name="accessibility_floating_button_hidden_notification_text" msgid="1457021647040915658">"אפשר להקיש כדי לראות את לחצן הנגישות"</string>
+ <string name="accessibility_floating_button_hidden_notification_title" msgid="4115036997406994799">"כפתור הנגישות מוסתר"</string>
+ <string name="accessibility_floating_button_hidden_notification_text" msgid="1457021647040915658">"אפשר ללחוץ כדי לראות את כפתור הנגישות"</string>
<string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"קיצור הדרך אל <xliff:g id="FEATURE_NAME">%s</xliff:g> הוסר"</string>
<string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{קיצור הדרך הוסר}one{# קיצורי דרך הוסרו}two{# קיצורי דרך הוסרו}other{# קיצורי דרך הוסרו}}"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"העברה לפינה השמאלית העליונה"</string>
@@ -1214,7 +1215,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"נבחר מכשיר אחד"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"נבחרו <xliff:g id="COUNT">%1$d</xliff:g> מכשירים"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(מנותק)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"לא ניתן להחליף. צריך להקיש כדי לנסות שוב."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"לא ניתן להחליף. צריך ללחוץ כדי לנסות שוב."</string>
<string name="media_output_dialog_pairing_new" msgid="5098212763195577270">"חיבור מכשיר"</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"אפליקציה לא ידועה"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"‏עצירת ההעברה (casting)"</string>
@@ -1245,7 +1246,7 @@
<string name="copy_to_clipboard_a11y_action" msgid="4312789069718446749">"העתקה ללוח."</string>
<string name="basic_status" msgid="2315371112182658176">"פתיחת שיחה"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"ווידג\'טים של שיחות"</string>
- <string name="select_conversation_text" msgid="3376048251434956013">"יש להקיש על שיחה כדי להוסיף אותה למסך הבית"</string>
+ <string name="select_conversation_text" msgid="3376048251434956013">"יש ללחוץ על שיחה כדי להוסיף אותה למסך הבית"</string>
<string name="no_conversations_text" msgid="5354115541282395015">"השיחות האחרונות שלך יופיעו כאן"</string>
<string name="priority_conversations" msgid="3967482288896653039">"שיחות בעדיפות גבוהה"</string>
<string name="recent_conversations" msgid="8531874684782574622">"שיחות אחרונות"</string>
@@ -1280,17 +1281,16 @@
<string name="new_status_content_description" msgid="6046637888641308327">"הסטטוס של <xliff:g id="NAME">%1$s</xliff:g> עודכן: ‏<xliff:g id="STATUS">%2$s</xliff:g>"</string>
<string name="person_available" msgid="2318599327472755472">"אונליין"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"בעיה בקריאת מדדי הסוללה"</string>
- <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"יש להקיש כדי להציג מידע נוסף"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"יש ללחוץ כדי להציג מידע נוסף"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"לא הוגדרה"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"הזנת קוד נעילת המסך"</string>
- <string name="accessibility_side_fingerprint_indicator_label" msgid="1673807833352363712">"צריך לגעת בחיישן טביעות האצבע. זה הלחצן הקצר יותר בצד של הטלפון"</string>
+ <string name="accessibility_side_fingerprint_indicator_label" msgid="1673807833352363712">"צריך לגעת בחיישן טביעות האצבע. זה הכפתור הקצר יותר בצד של הטלפון"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"חיישן טביעות אצבע"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"אימות"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"הזנת מכשיר"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"שימוש בטביעת אצבע כדי לפתוח"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"נדרש אימות. יש לגעת בחיישן טביעות האצבע כדי לבצע אימות."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"שיחה פעילה"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"חבילת גלישה"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"מחובר"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"מחובר באופן זמני"</string>
@@ -1300,7 +1300,7 @@
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"אין רשתות זמינות אחרות"</string>
<string name="all_network_unavailable" msgid="4112774339909373349">"אין רשתות זמינות"</string>
<string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
- <string name="tap_a_network_to_connect" msgid="1565073330852369558">"כדי להתחבר לרשת צריך להקיש עליה"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"כדי להתחבר לרשת צריך ללחוץ עליה"</string>
<string name="unlock_to_view_networks" msgid="5072880496312015676">"צריך לבטל את הנעילה כדי להציג את הרשתות"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"בתהליך חיפוש רשתות…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"נכשל הניסיון להתחבר לרשת"</string>
@@ -1326,7 +1326,7 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"עריכת הטקסט שהועתק"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"עריכת התמונה שהועתקה"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"שליחה למכשיר בקרבת מקום"</string>
- <string name="clipboard_text_hidden" msgid="7926899867471812305">"יש להקיש כדי להציג"</string>
+ <string name="clipboard_text_hidden" msgid="7926899867471812305">"יש ללחוץ כדי להציג"</string>
<string name="clipboard_text_copied" msgid="5100836834278976679">"הטקסט הועתק"</string>
<string name="clipboard_image_copied" msgid="3793365360174328722">"התמונה הועתקה"</string>
<string name="clipboard_content_copied" msgid="144452398567828145">"התוכן הועתק"</string>
@@ -1340,7 +1340,7 @@
<string name="dream_overlay_location_active" msgid="6484763493158166618">"המיקום פעיל"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"‏Wi‑Fi לא זמין"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"מצב עדיפות"</string>
- <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ההתראה מוגדרת"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"השעון המעורר מוגדר"</string>
<string name="dream_overlay_status_bar_camera_off" msgid="5273073778969890823">"המצלמה כבויה"</string>
<string name="dream_overlay_status_bar_mic_off" msgid="8366534415013819396">"המיקרופון כבוי"</string>
<string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"המצלמה והמיקרופון כבויים"</string>
@@ -1433,17 +1433,18 @@
<string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ריבוי משימות"</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_app_shortcuts" msgid="8010249408308587117">"מקשי קיצור לאפליקציות"</string>
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"האפליקציה הנוכחית"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"נגישות"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"מקשי קיצור"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"התאמה אישית של מקשי הקיצור"</string>
+ <!-- no translation found for shortcut_helper_customize_mode_title (8327297960035006036) -->
+ <skip />
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"להסיר את קיצור הדרך?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"לאפס לברירת המחדל?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"צריך להקיש על מקש כדי להקצות מקש קיצור"</string>
<string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"קיצור הדרך יימחק לתמיד."</string>
<string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"הפעולה הזו תמחק לתמיד את כל קיצורי הדרך שמותאמים אישית."</string>
- <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"קיצורי דרך לחיפוש"</string>
+ <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"חיפוש מקשי קיצור"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"אין תוצאות חיפוש"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"סמל הכיווץ"</string>
<string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"סמל מקש הפעולה (\"מטא\")"</string>
@@ -1465,6 +1466,10 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"שילוב המקשים הזה כבר בשימוש. אפשר לנסות מקש אחר."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"לא ניתן להגדיר את קיצור הדרך."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <!-- no translation found for shortcut_helper_add_shortcut_button_label (7655779534665954910) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_delete_shortcut_button_label (3148773472696137052) -->
+ <skip />
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ניווט באמצעות המקלדת"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"מידע על מקשי קיצור"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ניווט באמצעות לוח המגע"</string>
@@ -1510,13 +1515,13 @@
<string name="redacted_notification_single_line_text" msgid="8684166405005242945">"צריך לבטל את הנעילה כדי לראות"</string>
<string name="contextual_education_dialog_title" msgid="4630392552837487324">"חינוך בהתאם להקשר"</string>
<string name="back_edu_notification_title" msgid="5624780717751357278">"אפשר להשתמש בלוח המגע כדי לחזור אחורה"</string>
- <string name="back_edu_notification_content" msgid="2497557451540954068">"מחליקים ימינה או שמאלה עם שלוש אצבעות. ניתן להקיש כדי לקבל מידע נוסף על התנועות."</string>
+ <string name="back_edu_notification_content" msgid="2497557451540954068">"מחליקים ימינה או שמאלה עם שלוש אצבעות. ניתן ללחוץ כדי לקבל מידע נוסף על התנועות."</string>
<string name="home_edu_notification_title" msgid="6097902076909654045">"איך להשתמש בלוח המגע כדי לעבור למסך הבית"</string>
- <string name="home_edu_notification_content" msgid="6631697734535766588">"מחליקים למעלה עם שלוש אצבעות. אפשר להקיש כדי לקבל מידע נוסף על התנועות."</string>
+ <string name="home_edu_notification_content" msgid="6631697734535766588">"מחליקים למעלה עם שלוש אצבעות. אפשר ללחוץ כדי לקבל מידע נוסף על התנועות."</string>
<string name="overview_edu_notification_title" msgid="1265824157319562406">"איך להשתמש בלוח המגע כדי לראות את האפליקציות האחרונות"</string>
- <string name="overview_edu_notification_content" msgid="3578204677648432500">"מחליקים למעלה ולוחצים לחיצה ארוכה עם שלוש אצבעות. אפשר להקיש כדי לקבל מידע נוסף על התנועות."</string>
+ <string name="overview_edu_notification_content" msgid="3578204677648432500">"מחליקים למעלה ולוחצים לחיצה ארוכה עם שלוש אצבעות. אפשר ללחוץ כדי לקבל מידע נוסף על התנועות."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"איך להשתמש במקלדת כדי לראות את כל האפליקציות"</string>
- <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"בכל שלב אפשר ללחוץ על מקש הפעולה. ניתן להקיש כדי לקבל מידע נוסף על התנועות."</string>
+ <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"בכל שלב אפשר ללחוץ על מקש הפעולה. ניתן ללחוץ כדי לקבל מידע נוסף על התנועות."</string>
<string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"התכונה \'מעומעם במיוחד\' נוספה לפס ההזזה לבהירות"</string>
<string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"עכשיו אפשר להפוך את המסך למעומעם במיוחד באמצעות הפחתה נוספת של רמת הבהירות.\n\nהתכונה הזו היא עכשיו חלק מפס ההזזה לבהירות, לכן קיצורי הדרך לתכונה \'מעומעם במיוחד\' נמצאים בתהליך הסרה."</string>
<string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"הסרה של קיצורי הדרך לתכונה \'מעומעם במיוחד\'"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 4634a50c7199..8941217e8cbd 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"衛生、接続状態良好"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"衛生、接続利用可能"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"衛星 SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"緊急通報または SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>、<xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>。"</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"圏外"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"レベル 1"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"デバイスを入力"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"指紋を使って開いてください"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"認証が必要です。指紋認証センサーをタッチして認証してください。"</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"通話中"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"モバイルデータ"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"接続済み"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"一時的に接続されています"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"現在のアプリ"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ユーザー補助"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"キーボード ショートカット"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"キーボード ショートカットのカスタマイズ"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"ショートカットのカスタマイズ"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"ショートカットを削除しますか?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"デフォルトにリセットしますか?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"ショートカットを割り当てるキーを押してください"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"このキーの組み合わせはすでに使用されています。別のキーを試してください。"</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"ショートカットを設定できません。"</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"ショートカットを追加"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"ショートカットを削除"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"キーボードを使用して移動する"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"キーボード ショートカットの詳細"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"タッチパッドを使用して移動する"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index fc0b81dbcca5..6937048c1826 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"კარგი სატელიტური კავშირი"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ხელმისაწვდომია სატელიტური კავშირი"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"სატელიტური SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"გადაუდებელი ზარი ან SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"სიგნალი არ არის"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"ერთი ხაზი"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"მოწყობილობის შეყვანა"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"გასახსნელად გამოიყენეთ თითის ანაბეჭდი"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"საჭიროა ავტორიზაცია. ავტორიზაციისთვის შეეხეთ თითის ანაბეჭდის სენსორს."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"მიმდინარე ზარი"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"მობილური ინტერნეტი"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"დაკავშირებული"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"დროებით დაკავშირებული"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"მიმდინარე აპი"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"მისაწვდომობა"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"კლავიატურის მალსახმობები"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"კლავიატურის მალსახმობების მორგება"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"მალსახმობების მორგება"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"გსურთ მალსახმობის წაშლა?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"გსურთ ნაგულისხმევზე გადაყენება?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"მალსახმობის მინიჭებისთვის დააჭირეთ კლავიშს"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"კლავიშების კომბინაცია უკვე გამოიყენება. ცადეთ სხვა კლავიში."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"მალსახმობის დაყენება ვერ ხერხდება."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"მალსახმობის დამატება"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"მალსახმობის წაშლა"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ნავიგაცია კლავიატურის გამოყენებით"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"კლავიატურის მალსახმობების სწავლა"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ნავიგაცია სენსორული პანელის გამოყენებით"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 643a1c27b675..d6f0a006f588 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Жерсерік, байланыс жақсы."</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Жерсерік, байланыс бар."</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Құтқару қызметіне қоңырау шалу немесе SOS сигналын жіберу"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"сигнал жоқ"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"бір жолақ"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"құрылғыны енгізу"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Ашу үшін саусақ ізін пайдаланыңыз."</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Аутентификациядан өту қажет. Ол үшін саусақ ізін оқу сканерін түртіңіз."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Ағымдағы қоңырау"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобильдік интернет"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Жалғанды"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Уақытша байланыс орнатылды."</string>
@@ -1437,13 +1437,13 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Қолданыстағы қолданба"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Арнайы мүмкіндіктер"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Перне тіркесімдері"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Пернелер тіркесімін бейімдеу"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Пернелер тіркесімін бейімдеу"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Тіркесімді өшіру керек пе?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Әдепкі тіркесімге қайтару керек пе?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Тіркесім тағайындау үшін пернені басыңыз."</string>
<string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Арнаулы тіркесіміңіз біржола жойылады."</string>
<string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Мұндайда барлық арнаулы тіркесім біржола жойылады."</string>
- <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Іздеу жылдам пәрмендері"</string>
+ <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Тіркесімдерді іздеу"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Іздеу нәтижелері жоқ."</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Жию белгішесі"</string>
<string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Әрекет немесе Meta пернесінің белгішесі"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Бұл пернелер тіркесімі қазір қолданыста. Басқа перне таңдаңыз."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Перне тіркесімін орнату мүмкін емес."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Жылдам пәрмен қосу"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Жылдам пәрменді жою"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Пернетақтамен жұмыс істеңіз"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Перне тіркесімдерін үйреніңіз."</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Сенсорлық тақтамен жұмыс істеңіз"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 239e2a9764a0..efbc0aa0d68c 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ផ្កាយរណប មានការតភ្ជាប់ល្អ"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ផ្កាយរណប អាចតភ្ជាប់បាន"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"ការប្រកាសអាសន្នតាមផ្កាយរណប"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"ការហៅទៅលេខសង្គ្រោះបន្ទាន់ ឬ SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>។"</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"គ្មានសញ្ញា"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"មួយកាំ"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"បញ្ចូល​ឧបករណ៍"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ប្រើស្នាមម្រាមដៃ ដើម្បីបើក"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"តម្រូវឱ្យ​មាន​ការផ្ទៀងផ្ទាត់។ សូមចុច​ឧបករណ៍​ចាប់ស្នាមម្រាមដៃ ដើម្បី​ផ្ទៀងផ្ទាត់​។"</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"ការ​ហៅដែលកំពុងដំណើរការ"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"ទិន្នន័យ​ទូរសព្ទចល័ត"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"បានភ្ជាប់"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"បានភ្ជាប់ជាបណ្ដោះអាសន្ន"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"កម្មវិធីបច្ចុប្បន្ន"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ភាពងាយស្រួល"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"ផ្លូវកាត់​ក្ដារ​ចុច"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"ប្ដូរ​ផ្លូវកាត់​ក្ដារ​ចុចតាម​បំណង"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"ប្ដូរ​ផ្លូវ​កាត់តាម​បំណង"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"ដក​ផ្លូវកាត់​ចេញឬ?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"កំណត់ឡើងវិញទៅលំនាំដើមឬ?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"ចុចគ្រាប់ចុច ដើម្បីកំណត់ផ្លូវ​កាត់"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"បន្សំគ្រាប់ចុចនេះត្រូវបានប្រើប្រាស់ហើយ។ សាកល្បងគ្រាប់ចុចផ្សេង។"</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"មិនអាចកំណត់ផ្លូវកាត់បានទេ។"</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"បញ្ចូល​ផ្លូវកាត់"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"លុបផ្លូវកាត់"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"រុករកដោយប្រើក្ដារចុចរបស់អ្នក"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ស្វែងយល់អំពីផ្លូវកាត់​ក្ដារ​ចុច"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"រុករកដោយប្រើផ្ទាំងប៉ះរបស់អ្នក"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 0b0caa4e51eb..ded267feee65 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ಸ್ಯಾಟಲೈಟ್‌, ಕನೆಕ್ಷನ್ ಉತ್ತಮವಾಗಿದೆ"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ಸ್ಯಾಟಲೈಟ್, ಕನೆಕ್ಷನ್ ಲಭ್ಯವಿದೆ"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"ಸ್ಯಾಟಲೈಟ್ SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"ತುರ್ತು ಕರೆಗಳು ಅಥವಾ SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"ಸಿಗ್ನಲ್ ಇಲ್ಲ"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"ಒಂದು ಬಾರ್"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ಸಾಧನವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ತೆರೆಯುವುದಕ್ಕಾಗಿ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್ನು ಬಳಸಿ"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ದೃಢೀಕರಣದ ಅವಶ್ಯಕತೆಯಿದೆ. ದೃಢೀಕರಿಸಲು ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಅನ್ನು ಸ್ಪರ್ಶಿಸಿ."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"ಚಾಲ್ತಿಯಲ್ಲಿರುವ ಕರೆ"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"ಮೊಬೈಲ್ ಡೇಟಾ"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"ತಾತ್ಕಾಲಿಕವಾಗಿ ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"ಪ್ರಸ್ತುತ ಆ್ಯಪ್"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಿ"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಿ"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"ಶಾರ್ಟ್‌ಕಟ್ ಅನ್ನು ತೆಗೆದುಹಾಕಬೇಕೇ?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ಡೀಫಾಲ್ಟ್‌ಗೆ ರೀಸೆಟ್ ಮಾಡಬೇಕೆ?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"ಶಾರ್ಟ್‌ಕಟ್ ಅನ್ನು ನಿಯೋಜಿಸಲು ಕೀಯನ್ನು ಒತ್ತಿರಿ"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"ಕೀ ಸಂಯೋಜನೆಯು ಈಗಾಗಲೇ ಬಳಕೆಯಲ್ಲಿದೆ. ಮತ್ತೊಂದು ಕೀ ಬಳಸಿ ನೋಡಿ."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"ಶಾರ್ಟ್‌ಕಟ್‌ ಅನ್ನು ಸೆಟ್‌ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"ಶಾರ್ಟ್‌ಕಟ್ ಸೇರಿಸಿ"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"ಶಾರ್ಟ್‌ಕಟ್ ಅಳಿಸಿ"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ ಬಳಸಿ ನ್ಯಾವಿಗೇಟ್ ಮಾಡಿ"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಕಲಿಯಿರಿ"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ನಿಮ್ಮ ಟಚ್‌ಪ್ಯಾಡ್ ಬಳಸಿ ನ್ಯಾವಿಗೇಟ್ ಮಾಡಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 14736604bcf8..732c9bc8620c 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"위성, 연결 상태 양호"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"위성, 연결 가능"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"위성 긴급 SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"긴급 전화 또는 SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"신호가 없습니다"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"신호 막대가 1개입니다"</string>
@@ -882,7 +883,7 @@
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"앱 목록 열기"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"설정 열기"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"어시스턴트 열기"</string>
- <string name="group_system_lock_screen" msgid="7391191300363416543">"잠금 화면"</string>
+ <string name="group_system_lock_screen" msgid="7391191300363416543">"화면 잠금"</string>
<string name="group_system_quick_memo" msgid="3764560265935722903">"메모 작성"</string>
<string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"멀티태스킹"</string>
<string name="system_multitasking_rhs" msgid="8779289852395243004">"앱이 오른쪽에 오도록 화면 분할 사용"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"기기 입력"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"지문으로 열기"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"인증이 필요합니다. 지문 센서를 터치하여 인증하세요."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"진행 중인 통화"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"모바일 데이터"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"연결됨"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"일시적으로 연결됨"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"현재 앱"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"접근성"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"단축키"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"단축키 맞춤설정"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"단축키 맞춤설정"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"단축키를 삭제하시겠어요?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"기본값으로 재설정하시겠어요?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"키를 눌러 단축키 지정"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"이미 사용 중인 키 조합입니다. 다른 키를 사용해 보세요."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"단축키를 설정할 수 없습니다."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"단축키 추가"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"단축키 삭제"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"키보드를 사용하여 이동"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"단축키에 관해 알아보세요."</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"터치패드를 사용하여 이동"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index ad70e7961dc6..eb5960fa23cd 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Спутник, байланыш жакшы"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Спутник, байланыш бар"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Спутник SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Шашылыш чалуулар же SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"сигнал жок"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"бир мамыча"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"түзмөккө кирүү"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Манжаңыздын изи менен ачыңыз"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Аныктыкты текшерүү талап кылынат. Аныктыгын текшерүү үчүн манжа изинин сенсоруна тийип коюңуз."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Учурдагы чалуу"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилдик трафик"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Туташты"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Убактылуу туташып турат"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Учурдагы колдонмо"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Атайын мүмкүнчүлүктөр"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Ыкчам баскычтар"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Ыкчам баскычтарды ыңгайлаштыруу"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Ыкчам баскычтарды тууралоо"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Ыкчам баскыч өчүрүлсүнбү?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Баштапкы абалга келтиресизби?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Ыкчам баскычты дайындоо үчүн баскычты басыңыз"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Ачкычтардын айкалышы колдонулууда. Башка ачкычты байкап көрүңүз."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Ыкчам баскычты коюу мүмкүн эмес."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Ыкчам баскыч кошуу"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Ыкчам баскычты өчүрүү"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Керектүү нерселерге баскычтоп аркылуу өтүү"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Ыкчам баскычтар тууралуу билип алыңыз"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Керектүү жерге сенсордук такта аркылуу өтөсүз"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 1c3d4110b793..19ddc7aa5c9a 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ດາວທຽມ, ການເຊື່ອມຕໍ່ດີ"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ດາວທຽມ, ການເຊື່ອມຕໍ່ທີ່ພ້ອມນຳໃຊ້"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS ດາວທຽມ"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"ໂທສຸກເສີນ ຫຼື SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"ບໍ່ມີສັນຍານ"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"1 ຂີດ"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ເຂົ້າອຸປະກອນ"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ໃຊ້ລາຍນິ້ວມືເພື່ອເປີດ"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ຕ້ອງພິສູດຢືນຢັນ. ແຕະໃສ່ເຊັນເຊີລາຍນິ້ວມືເພື່ອພິສູດຢືນຢັນ."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"ສາຍທີ່ສົນທະນາຢູ່"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"ອິນເຕີເນັດມືຖື"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"ເຊື່ອມຕໍ່ແລ້ວ"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"ເຊື່ອມຕໍ່ແລ້ວຊົ່ວຄາວ"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"ແອັບປັດຈຸບັນ"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ການຊ່ວຍເຂົ້າເຖິງ"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"ຄີລັດ"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"ປັບແຕ່ງຄີລັດ"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"ປັບແຕ່ງທາງລັດ"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"ລຶບທາງລັດອອກບໍ?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ຣີເຊັດກັບຄືນເປັນຄ່າເລີ່ມຕົ້ນບໍ?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"ກົດປຸ່ມເພື່ອກຳນົດທາງລັດ"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"ນໍາໃຊ້ປຸ່ມປະສົມຢູ່ແລ້ວ. ໃຫ້ລອງປຸ່ມອື່ນ."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"ຕັ້ງທາງລັດບໍ່ໄດ້."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"ເພີ່ມທາງລັດ"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"ລຶບທາງລັດ"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ນຳທາງໂດຍໃຊ້ແປ້ນພິມຂອງທ່ານ"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ສຶກສາຄີລັດ"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ນຳທາງໂດຍໃຊ້ແຜ່ນສຳຜັດຂອງທ່ານ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index eb6fd2d9eea7..71ce30db0a02 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Palydovas, geras ryšys"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Palydovas, pasiekiamas ryšys"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Prisijungimas prie palydovo kritiniu atveju"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Skambučiai pagalbos numeriu arba pagalbos iškvietimas kritiniu atveju"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"„<xliff:g id="CARRIER_NAME">%1$s</xliff:g>“, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"nėra signalo"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"viena juosta"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"pasiektumėte įrenginį"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Naudokite kontrolinį kodą, kad atidarytumėte"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Reikia nustatyti tapatybę. Nustatykite tapatybę palietę kontrolinio kodo jutiklį."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Vykstantis skambutis"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiliojo ryšio duomenys"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Prisijungta"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Laikinai prijungta"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Esama programa"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Pritaikomumas"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Spartieji klavišai"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Sparčiųjų klavišų tinkinimas"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Sparčiųjų klavišų tinkinimas"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Pašalinti spartųjį klavišą?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Iš naujo nustatyti numatytąjį nustatymą?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Paspauskite klavišą, kad priskirtumėte spartųjį klavišą"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Klavišų derinys jau naudojamas. Bandykite naudoti kitą klavišą."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Sparčiojo klavišo nustatyti negalima."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Pridėti spartųjį klavišą"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Ištrinti spartųjį klavišą"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naršykite naudodamiesi klaviatūra"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Sužinokite apie sparčiuosius klavišus"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naršykite naudodamiesi jutikline dalimi"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 7740d2d14c0f..271c081ea3a9 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelīts, labs savienojums"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelīts, ir pieejams savienojums"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelīta SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Ārkārtas izsaukumi vai ārkārtas zvani"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"nav signāla"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"viena josla"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"izmantotu ierīci"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Atvēršanai izmantojiet pirksta nospiedumu"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Nepieciešama autentifikācija. Pieskarieties pirksta nospieduma sensoram, lai veiktu autentificēšanu."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Notiekošs zvans"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilie dati"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Ir izveidots savienojums"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Īslaicīgi izveidots savienojums"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Pašreizējā lietotne"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Pieejamība"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Īsinājumtaustiņi"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Īsinājumtaustiņu pielāgošana"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Īsinājumtaustiņu pielāgošana"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Vai noņemt saīsni?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Vai atiestatīt noklusējuma vērtības?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Lai piešķirtu īsinājumtaustiņu, nospiediet taustiņu"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Taustiņu kombinācija jau tiek izmantota. Izmēģiniet citu taustiņu."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Nevar iestatīt saīsni."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Pievienot saīsni"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Dzēst saīsni"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Pārvietošanās, izmantojot tastatūru"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Uzziniet par īsinājumtaustiņiem."</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Pārvietošanās, izmantojot skārienpaliktni"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index e4064e239b34..b478a5b38c4b 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Добра сателитска врска"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Достапна е сателитска врска"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Сателитски SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Итни повици или SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"нема сигнал"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"една цртичка"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"внесете уред"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Користете отпечаток за да се отвори"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Потребна е проверка. Допрете го сензорот за отпечаток за да автентицирате."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Тековен повик"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилен интернет"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Поврзано"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Привремено поврзано"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Тековна апликација"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Пристапност"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Кратенки од тастатура"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Приспособете ги кратенките од тастатурата"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Приспособете ги кратенките"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Да се отстрани кратенката?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Да се ресетира на стандардните поставки?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Притиснете копче за да доделите кратенка"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Комбинацијата на копчиња веќе се користи. Обидете се со друго копче."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Кратенката не може да се постави."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Додај кратенка"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Избриши кратенка"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Движете се со користење на тастатурата"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Научете ги кратенките од тастатурата"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Движете се со користење на допирната подлога"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 601e6a13e628..4885595c860b 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"സാറ്റലൈറ്റ്, മികച്ച കണക്ഷൻ"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"സാറ്റലൈറ്റ്, കണക്ഷൻ ലഭ്യമാണ്"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"സാറ്റലൈറ്റ് SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"എമർജൻസി കോൾ അല്ലെങ്കിൽ SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"സിഗ്നൽ ഇല്ല"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"ഒരു ബാർ"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ഉപകരണം നൽകുക"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"തുറക്കുന്നതിന് നിങ്ങളുടെ ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കുക"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"പരിശോധിച്ചുറപ്പിക്കേണ്ടതുണ്ട്. പരിശോധിച്ചുറപ്പിക്കാൻ, വിരലടയാള സെൻസറിൽ സ്‌പർശിക്കുക."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"കോളിലാണ്"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"മൊബൈൽ ഡാറ്റ"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"കണക്റ്റ് ചെയ്തു"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"താൽക്കാലികമായി കണക്റ്റ് ചെയ്തിരിക്കുന്നു"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"നിലവിലെ ആപ്പ്"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ഉപയോഗസഹായി"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"കീബോഡ് കുറുക്കുവഴികൾ"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"കീബോർഡ് കുറുക്കുവഴികൾ ഇഷ്ടാനുസൃതമാക്കുക"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"കുറുക്കുവഴികൾ ഇഷ്ടാനുസൃതമാക്കുക"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"കുറുക്കുവഴി നീക്കം ചെയ്യണോ?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ഡിഫോൾട്ടിലേക്ക് തിരികെ റീസെറ്റ് ചെയ്യണോ?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"കുറുക്കുവഴി അസൈൻ ചെയ്യാൻ കീ അമർത്തുക"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"കീ കോമ്പിനേഷൻ ഇതിനകം ഉപയോഗത്തിലുണ്ട്. മറ്റൊരു കീ പരീക്ഷിക്കുക."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"കുറുക്കുവഴി സജ്ജീകരിക്കാനാകില്ല."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"കുറുക്കുവഴി ചേർക്കുക"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"കുറുക്കുവഴി ഇല്ലാതാക്കുക"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"നിങ്ങളുടെ കീബോർഡ് ഉപയോഗിച്ച് നാവിഗേറ്റ് ചെയ്യുക"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"കീബോർഡ് കുറുക്കുവഴികൾ മനസ്സിലാക്കുക"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"നിങ്ങളുടെ ടച്ച്‌പാഡ് ഉപയോഗിച്ച് നാവിഗേറ്റ് ചെയ്യുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index b865eedbf26e..52dff9e8afdd 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Хиймэл дагуул, холболт сайн байна"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Хиймэл дагуул, холболт боломжтой"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Хиймэл дагуул SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Яаралтай дуудлага эсвэл SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"дохио байхгүй"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"нэг шон"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"төхөөрөмж оруулах"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Нээхийн тулд хурууны хээг ашиглана уу"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Баталгаажуулалт шаардлагатай. Баталгаажуулахын тулд хурууны хээ мэдрэгчид хүрнэ үү."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Үргэлжилж буй дуудлага"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобайл дата"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Холбогдсон"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Түр зуур холбогдсон"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Одоогийн апп"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Хандалт"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Товчлуурын шууд холбоос"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Товчлуурын шууд холбоосыг өөрчлөх"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Товчлолыг өөрчлөх"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Товчлолыг хасах уу?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Өгөгдмөл рүү буцааж шинэчлэх үү?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Товчлол оноохын тулд товч дарна уу"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Товчийн хослолыг аль хэдийн ашиглаж байна. Өөр товч туршиж үзнэ үү."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Товчлол тохируулах боломжгүй."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Товчлол нэмэх"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Товчлол устгах"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Гараа ашиглан шилжих"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Товчлуурын шууд холбоосыг мэдэж аваарай"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Мэдрэгч самбараа ашиглан шилжээрэй"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index e257ba159788..85ae835df9fe 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"सॅटेलाइट, चांगले कनेक्शन"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"सॅटेलाइट, कनेक्शन उपलब्ध"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"सॅटेलाइट SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"आणीबाणी कॉल किंवा SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"कोणताही सिग्नल नाही"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"एक बार"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"डिव्हाइस एंटर करा"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"उघडण्यासाठी फिंगरप्रिंट वापरा"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ऑथेंटिकेशन आवश्यक आहे. ऑथेंटिकेट करण्यासाठी फिंगरप्रिंट सेन्सरला स्पर्श करा."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"सुरू असलेला कॉल"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"मोबाइल डेटा"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"कनेक्ट केले आहे"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"तात्पुरते कनेक्ट केलेले"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"सध्याचे अ‍ॅप"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"अ‍ॅक्सेसिबिलिटी"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"कीबोर्ड शॉर्टकट"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"कीबोर्ड शॉर्टकट कस्टमाइझ करा"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"शॉर्टकट कस्टमाइझ करा"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"शॉर्टकट काढून टाकायचा आहे का?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"डीफॉल्टवर पुन्हा रीसेट करायचे आहे का?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"शॉर्टकट असाइन करण्यासाठी की प्रेस करा"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"की कॉम्बिनेशन आधीपासून वापरले जात आहे. दुसरी की वापरून पहा."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"शॉर्टकट सेट करू शकत नाही."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"शॉर्टकट जोडा"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"शॉर्टकट हटवा"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"तुमचा कीबोर्ड वापरून नेव्हिगेट करा"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"कीबोर्ड शॉर्टकट जाणून घ्या"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"तुमचा टचपॅड वापरून नेव्हिगेट करा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index bf65859aab7e..b5f0d147f972 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, sambungan yang baik"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, sambungan tersedia"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via Satelit"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Panggilan kecemasan atau SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"tiada isyarat"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"satu bar"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"akses peranti"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gunakan cap jari untuk membuka"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Pengesahan diperlukan. Sentuh penderia cap jari untuk pengesahan."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Panggilan sedang berlangsung"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Data mudah alih"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Disambungkan"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Disambungkan buat sementara waktu"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Apl Semasa"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Kebolehaksesan"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Pintasan papan kekunci"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Sesuaikan pintasan papan kekunci"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Sesuaikan pintasan"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Alih keluar pintasan?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Tetapkan kembali kepada lalai?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Tekan kekunci untuk menetapkan pintasan"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Gabungan kekunci sudah digunakan. Cuba kekunci lain."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Pintasan tidak boleh ditetapkan."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Tambahkan pintasan"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Padamkan pintasan"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigasi menggunakan papan kekunci"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Ketahui pintasan papan kekunci"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigasi menggunakan pad sentuh anda"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 1c4055687d26..d24c4a0b1631 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ဂြိုဟ်တု၊ ချိတ်ဆက်မှု ကောင်းသည်"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ဂြိုဟ်တု၊ ချိတ်ဆက်မှု ရနိုင်သည်"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"အရေးပေါ်ဖုန်းခေါ်ခြင်း (သို့) SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>၊ <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>။"</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"လိုင်းမရှိပါ"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"တစ်ဘား"</string>
@@ -830,7 +831,7 @@
<string name="keyboard_key_button_template" msgid="8005673627272051429">"ခလုတ် <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="3734400625170020657">"ပင်မ"</string>
<string name="keyboard_key_back" msgid="4185420465469481999">"နောက်သို့"</string>
- <string name="keyboard_key_tab" msgid="4592772350906496730">"တဘ်ခလုတ်"</string>
+ <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string>
<string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string>
<string name="keyboard_key_enter" msgid="8633362970109751646">"Enter ခလုတ်"</string>
<string name="keyboard_key_backspace" msgid="4095278312039628074">"နောက်ပြန်ခလုတ်"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"စက်ပစ္စည်းသို့ ဝင်ရန်"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ဖွင့်ရန် လက်ဗွေကို သုံးပါ"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"အထောက်အထားစိစစ်ခြင်း လိုအပ်သည်။ အထောက်အထားစိစစ်ရန် လက်ဗွေ အာရုံခံကိရိယာကို ထိပါ။"</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"လက်ရှိခေါ်ဆိုမှု"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"မိုဘိုင်းဒေတာ"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"ချိတ်ဆက်ထားသည်"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"ယာယီချိတ်ဆက်ထားသည်"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"လက်ရှိအက်ပ်"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"အများသုံးနိုင်မှု"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"လက်ကွက်ဖြတ်လမ်းများ"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"လက်ကွက်ဖြတ်လမ်းများကို စိတ်ကြိုက်လုပ်ခြင်း"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"ဖြတ်လမ်းများ စိတ်ကြိုက်ပြင်ဆင်ခြင်း"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"ဖြတ်လမ်းလင့်ခ် ဖယ်ရှားမလား။"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"မူရင်းသို့ ပြန်လည်ပြင်ဆင်သတ်မှတ်မလား။"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"ဖြတ်လမ်းလင့်ခ်သတ်မှတ်ရန် ကီးကို နှိပ်ပါ"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"ကီးပေါင်းစပ်ခြင်းကို သုံးနေပြီးဖြစ်သည်။ အခြားကီးကို စမ်းကြည့်ပါ။"</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"ဖြတ်လမ်းလင့်ခ် သတ်မှတ်၍မရပါ။"</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"ဖြတ်လမ်းလင့်ခ် ထည့်ရန်"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"ဖြတ်လမ်းလင့်ခ် ဖျက်ရန်"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"သင့်ကီးဘုတ်ကိုသုံး၍ လမ်းညွှန်ခြင်း"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"လက်ကွက်ဖြတ်လမ်းများကို လေ့လာပါ"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"သင့်တာ့ချ်ပက်ကိုသုံး၍ လမ်းညွှန်ခြင်း"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 0b68bd921c6f..871ffe921f89 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellitt – god tilkobling"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellitt – tilkobling tilgjengelig"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS-alarm via satellitt"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Nødanrop eller SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"ikke noe signal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"én strek"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"åpne enheten"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Bruk fingeravtrykk for å åpne"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentisering kreves. Trykk på fingeravtrykkssensoren for å autentisere."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Aktiv samtale"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobildata"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Tilkoblet"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Koblet til midlertidig"</string>
@@ -1437,13 +1437,13 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktiv app"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Tilgjengelighet"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Hurtigtaster"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Tilpass hurtigtastene"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Tilpass snarveier"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Vil du fjerne hurtigtasten?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Vil du tilbakestille til standard?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Trykk på en tast for å tilordne hurtigtasten"</string>
<string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Dette fører til at den egendefinerte hurtigtasten slettes permanent."</string>
<string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Dette fører til at alle de egendefinerte snarveiene dine slettes permanent."</string>
- <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Snarveier til søk"</string>
+ <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Søk etter snarveier"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ingen søkeresultater"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Skjul-ikon"</string>
<string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Handlings- eller Meta-tast-ikon"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Tastekombinasjonen brukes allerede. Prøv en annen tast."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Kan ikke angi snarveien."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Legg til snarvei"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Slett snarveien"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviger med tastaturet"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Lær deg hurtigtaster"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviger med styreflaten"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 818809b4acfc..58307c49ada7 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"स्याटलाइट, राम्रो कनेक्सन"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"स्याटलाइट, कनेक्सन उपलब्ध छ"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"स्याटलाइट SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"आपत्कालीन कल वा SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>।"</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"सिग्नल छैन"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"एउटा बार"</string>
@@ -884,7 +885,7 @@
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"एसिस्टेन्ट खोल्नुहोस्"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"स्क्रिन लक गर्नुहोस्"</string>
<string name="group_system_quick_memo" msgid="3764560265935722903">"नोट लेख्नुहोस्"</string>
- <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"एकै पटक एकभन्दा बढी एप चलाउन मिल्ने सुविधा"</string>
+ <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"मल्टिटास्किङ"</string>
<string name="system_multitasking_rhs" msgid="8779289852395243004">"हालको एप दायाँ भागमा पारेर स्प्लिट स्क्रिन प्रयोग गर्नुहोस्"</string>
<string name="system_multitasking_lhs" msgid="7348595296208696452">"हालको एप बायाँ भागमा पारेर स्प्लिट स्क्रिन प्रयोग गर्नुहोस्"</string>
<string name="system_multitasking_full_screen" msgid="4940465971687159429">"फुल स्क्रिन प्रयोग गर्नुहोस्"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"डिभाइस हाल्नुहोस्"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"फिंगरप्रिन्ट प्रयोग गरी खोल्नुहोस्"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"पुष्टि गर्नु पर्ने हुन्छ। पुष्टि गर्न फिंगरप्रिन्ट सेन्सर छुनुहोस्।"</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"कल भइरहेको"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"मोबाइल डेटा"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"इन्टरनेटमा कनेक्ट गरिएको छ"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"यसमा केही समयका लागि कनेक्ट गरिएको हो"</string>
@@ -1430,20 +1430,20 @@
<string name="shortcut_helper_category_system" msgid="462110876978937359">"सिस्टम"</string>
<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>
+ <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"मल्टिटास्किङ"</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_current_app_shortcuts" msgid="4017840565974573628">"हालको एप"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"सर्वसुलभता"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"किबोर्डका सर्टकटहरू"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"किबोर्डका सर्टकटहरू कस्टमाइज गर्नुहोस्"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"सर्टकटहरू कस्टमाइज गर्नुहोस्"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"सर्टकट हटाउने हो?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"सर्टकट रिसेट गरी डिफल्ट बनाउने हो?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"सर्टकट असाइन गर्न की थिच्नुहोस्"</string>
<string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"यसो गर्नुभयो भने तपाईंको कस्टम सर्टकट सदाका लागि मेटिने छ।"</string>
<string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"तपाईंले यसो गर्नुभयो भने तपाईंका सबै कस्टम सर्टकटहरू सदाका लागि मेटाइने छन्।"</string>
- <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"खोजका सर्टकटहरू"</string>
+ <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"सर्टकटहरू खोज्नुहोस्"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"कुनै पनि खोज परिणाम भेटिएन"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"\"कोल्याप्स गर्नुहोस्\" आइकन"</string>
<string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"एक्सन वा Meta कीको आइकन"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"यो की कम्बिनेसन प्रयोग गरिसकिएको छ। अर्कै की प्रयोग गरी हेर्नुहोस्।"</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"सर्टकट सेट गर्न सकिएन।"</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"सर्टकट हाल्नुहोस्"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"सर्टकट मेटाउनुहोस्"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"किबोर्ड प्रयोग गरी नेभिगेट गर्नुहोस्"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"किबोर्डका सर्टकटहरू प्रयोग गर्न सिक्नुहोस्"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"टचप्याड प्रयोग गरी नेभिगेट गर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 546cd081af72..6e8d328c1896 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelliet, goede verbinding"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelliet, verbinding beschikbaar"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via satelliet"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Noodoproepen of SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"geen signaal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"1 streepje"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"apparaat opgeven"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gebruik vingerafdruk om te openen"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Verificatie vereist. Raak de vingerafdruksensor aan om de verificatie uit te voeren."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Actief gesprek"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiele data"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Verbonden"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Tijdelijk verbonden"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Huidige app"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Toegankelijkheid"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Sneltoetsen"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Sneltoetsen aanpassen"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Snelkoppelingen aanpassen"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Sneltoets verwijderen?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Resetten naar standaard?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Druk op de toets om de sneltoets toe te wijzen"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Toetsencombinatie is al in gebruik. Probeer een andere toets."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Sneltoets kan niet worden ingesteld."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Snelkoppeling toevoegen"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Snelkoppeling verwijderen"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigeren met je toetsenbord"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Leer sneltoetsen die je kunt gebruiken"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigeren met je touchpad"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index d035f6a88de0..9986c11b49fd 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ସାଟେଲାଇଟ, ଭଲ କନେକ୍ସନ"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ସାଟେଲାଇଟ, କନେକ୍ସନ ଉପଲବ୍ଧ"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"ସେଟେଲାଇଟ SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"ଜରୁରୀକାଳୀନ କଲ କିମ୍ବା SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>।"</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"କୌଣସି ସିଗନାଲ ନାହିଁ"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"ଗୋଟିଏ ବାର"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ଡିଭାଇସ୍ ବିଷୟରେ ସୂଚନା ଲେଖନ୍ତୁ"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ଖୋଲିବାକୁ ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ପ୍ରମାଣୀକରଣ ଆବଶ୍ୟକ। ପ୍ରମାଣୀକରଣ କରିବାକୁ ଟିପଚିହ୍ନ ସେନ୍ସରକୁ ସ୍ପର୍ଶ କରନ୍ତୁ।"</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"ଚାଲିଥିବା କଲ"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"ମୋବାଇଲ ଡାଟା"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"ସଂଯୋଗ କରାଯାଇଛି"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"ଅସ୍ଥାୟୀ ରୂପେ କନେକ୍ଟ କରାଯାଇଛି"</string>
@@ -1428,7 +1428,7 @@
<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>
- <string name="shortcut_helper_category_system_controls" msgid="3153344561395751020">"ସିଷ୍ଟମ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
+ <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>
<string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"ବର୍ତ୍ତମାନର ଆପ"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ଆକ୍ସେସିବିଲିଟୀ"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"କୀବୋର୍ଡ ସର୍ଟକଟ"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"କୀବୋର୍ଡ ସର୍ଟକଟଗୁଡ଼ିକୁ କଷ୍ଟମାଇଜ କରନ୍ତୁ"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"ସର୍ଟକଟଗୁଡ଼ିକୁ କଷ୍ଟମାଇଜ କରନ୍ତୁ"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"ସର୍ଟକଟକୁ କାଢ଼ି ଦେବେ?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ଡିଫଲ୍ଟରେ ପୁଣି ରିସେଟ କରିବେ?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"ସର୍ଟକଟ ଆସାଇନ କରିବା ପାଇଁ କୀ\'କୁ ଦବାନ୍ତୁ"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"କୀ କମ୍ବିନେସନ ପୂର୍ବରୁ ବ୍ୟବହାର କରାଯାଉଛି। ଅନ୍ୟ ଏକ କୀ ବ୍ୟବହାର କରି ଦେଖନ୍ତୁ।"</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"ସର୍ଟକଟ ସେଟ କରାଯାଇପାରିବ ନାହିଁ।"</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"ସର୍ଟକଟ ଯୋଗ କରନ୍ତୁ"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"ସର୍ଟକଟକୁ ଡିଲିଟ କରନ୍ତୁ"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ଆପଣଙ୍କ କୀବୋର୍ଡ ବ୍ୟବହାର କରି ନାଭିଗେଟ କରନ୍ତୁ"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"କୀବୋର୍ଡ ସର୍ଟକଟଗୁଡ଼ିକ ବିଷୟରେ ଜାଣନ୍ତୁ"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ଆପଣଙ୍କ ଟଚପେଡ ବ୍ୟବହାର କରି ନାଭିଗେଟ କରନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 7b718de7f074..45888847bc2e 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -351,7 +351,7 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ਚਮਕ"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"ਰੰਗ ਪਲਟਨਾ"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ਰੰਗ ਸੁਧਾਈ"</string>
- <string name="quick_settings_font_scaling_label" msgid="5289001009876936768">"ਫੌਂਟ ਦਾ ਆਕਾਰ"</string>
+ <string name="quick_settings_font_scaling_label" msgid="5289001009876936768">"ਫੌਂਟ ਸਾਈਜ਼"</string>
<string name="quick_settings_more_user_settings" msgid="7634653308485206306">"ਵਰਤੋਂਕਾਰਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"ਹੋ ਗਿਆ"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ਬੰਦ ਕਰੋ"</string>
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ਸੈਟੇਲਾਈਟ, ਕਨੈਕਸ਼ਨ ਵਧੀਆ ਹੈ"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ਸੈਟੇਲਾਈਟ, ਕਨੈਕਸ਼ਨ ਉਪਲਬਧ ਹੈ"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"ਸੈਟੇਲਾਈਟ SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"ਐਮਰਜੈਂਸੀ ਕਾਲਾਂ ਜਾਂ ਸਹਾਇਤਾ"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"ਕੋਈ ਸਿਗਨਲ ਨਹੀਂ"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"ਇੱਕ ਸਿਗਨਲ ਪੱਟੀ"</string>
@@ -1069,7 +1070,7 @@
<string name="privacy_type_media_projection" msgid="8136723828804251547">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ਕੋਈ ਸਿਰਲੇਖ ਨਹੀਂ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ਸਟੈਂਡਬਾਈ"</string>
- <string name="font_scaling_dialog_title" msgid="6273107303850248375">"ਫ਼ੌਂਟ ਦਾ ਆਕਾਰ"</string>
+ <string name="font_scaling_dialog_title" msgid="6273107303850248375">"ਫ਼ੌਂਟ ਸਾਈਜ਼"</string>
<string name="font_scaling_smaller" msgid="1012032217622008232">"ਛੋਟਾ ਕਰੋ"</string>
<string name="font_scaling_larger" msgid="5476242157436806760">"ਵੱਡਾ ਕਰੋ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ਵੱਡਦਰਸ਼ੀਕਰਨ Window"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ਡੀਵਾਈਸ ਵਿੱਚ ਦਾਖਲ ਹੋਵੋ"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ਖੋਲ੍ਹਣ ਲਈ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ਪ੍ਰਮਾਣੀਕਰਨ ਲੋੜੀਂਦਾ ਹੈ। ਪ੍ਰਮਾਣਿਤ ਕਰਨ ਲਈ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਨੂੰ ਸਪਰਸ਼ ਕਰੋ।"</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"ਜਾਰੀ ਕਾਲ"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"ਮੋਬਾਈਲ ਡਾਟਾ"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"ਕਨੈਕਟ ਹੈ"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"ਕੁਝ ਸਮੇਂ ਲਈ ਕਨੈਕਟ ਹੈ"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"ਮੌਜੂਦਾ ਐਪ"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ਪਹੁੰਚਯੋਗਤਾ"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ ਵਿਉਂਤਬੱਧ ਕਰੋ"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"ਸ਼ਾਰਟਕੱਟਾਂ ਨੂੰ ਵਿਉਂਤਬੱਧ ਕਰੋ"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"ਕੀ ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਹਟਾਉਣਾ ਹੈ?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ਕੀ ਵਾਪਸ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ \'ਤੇ ਰੀਸੈੱਟ ਕਰਨਾ ਹੈ?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"ਸ਼ਾਰਟਕੱਟ ਨਿਰਧਾਰਿਤ ਕਰਨ ਲਈ ਕੁੰਜੀ ਦਬਾਓ"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"ਕੁੰਜੀ ਸੁਮੇਲ ਪਹਿਲਾਂ ਹੀ ਵਰਤੋਂ ਵਿੱਚ ਹੈ। ਕੋਈ ਹੋਰ ਕੁੰਜੀ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਸੈੱਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।"</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"ਸ਼ਾਰਟਕੱਟ ਸ਼ਾਮਲ ਕਰੋ"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"ਸ਼ਾਰਟਕੱਟ ਮਿਟਾਓ"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ਆਪਣੇ ਕੀ-ਬੋਰਡ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਨੈਵੀਗੇਟ ਕਰੋ"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ਕੀ-ਬੋਰਡ ਦੇ ਸ਼ਾਰਟਕੱਟਾਂ ਬਾਰੇ ਜਾਣੋ"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ਆਪਣੇ ਟੱਚਪੈਡ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਨੈਵੀਗੇਟ ਕਰੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index b6dc2f61656c..67ca4393ee64 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelita – połączenie dobre"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelita – połączenie dostępne"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelitarne połączenie alarmowe"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Połączenia alarmowe lub SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"brak sygnału"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"1 pasek"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"otwórz urządzenie"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"By otworzyć, użyj odcisku palca"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Wymagane uwierzytelnienie. Dotknij czytnika liniii papilarnych, by uwierzytelnić."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Trwa rozmowa"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilna transmisja danych"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Połączono"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Tymczasowe połączenie"</string>
@@ -1437,13 +1437,13 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Bieżąca aplikacja"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Ułatwienia dostępu"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Skróty klawiszowe"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Dostosuj skróty klawiszowe"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Dostosuj skróty"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Usunąć skrót?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Zresetować do ustawień domyślnych?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Naciśnij klawisz, aby przypisać skrót"</string>
<string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Spowoduje to trwałe usunięcie skrótu niestandardowego."</string>
<string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Spowoduje to trwałe usunięcie wszystkich skrótów niestandardowych."</string>
- <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Skróty do wyszukiwania"</string>
+ <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Szukaj skrótów"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Brak wyników wyszukiwania"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona zwijania"</string>
<string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ikona klawisza działania/meta"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Ta kombinacja klawiszy jest już używana. Użyj innego klawisza."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Nie można ustawić skrótu."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Dodaj skrót"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Usuń skrót"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Nawiguj za pomocą klawiatury"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Dowiedz się więcej o skrótach klawiszowych"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Nawiguj za pomocą touchpada"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index e7bcaa25e7fb..ead72a21e432 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -688,7 +688,7 @@
<string name="stream_system" msgid="7663148785370565134">"Sistema"</string>
<string name="stream_ring" msgid="7550670036738697526">"Toques"</string>
<string name="stream_music" msgid="2188224742361847580">"Mídia"</string>
- <string name="stream_alarm" msgid="16058075093011694">"Alarme"</string>
+ <string name="stream_alarm" msgid="16058075093011694">"Alarmes"</string>
<string name="stream_notification" msgid="7930294049046243939">"Notificações"</string>
<string name="stream_bluetooth_sco" msgid="6234562365528664331">"Bluetooth"</string>
<string name="stream_dtmf" msgid="7322536356554673067">"Multifrequência de dois tons"</string>
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satélite, conexão boa"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, conexão disponível"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via satélite"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Chamadas de emergência ou SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"sem sinal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"uma barra"</string>
@@ -871,7 +872,7 @@
<string name="keyboard_shortcut_a11y_filter_input" msgid="4589316004510335529">"Mostrando atalhos de entrada"</string>
<string name="keyboard_shortcut_a11y_filter_open_apps" msgid="6175417687221004059">"Mostrando atalhos que abrem apps"</string>
<string name="keyboard_shortcut_a11y_filter_current_app" msgid="7944592357493737911">"Mostrando atalhos do app atual"</string>
- <string name="group_system_access_notification_shade" msgid="1619028907006553677">"Mostrar as notificações"</string>
+ <string name="group_system_access_notification_shade" msgid="1619028907006553677">"Ver notificações"</string>
<string name="group_system_full_screenshot" msgid="5742204844232667785">"Fazer uma captura de tela"</string>
<string name="group_system_access_system_app_shortcuts" msgid="8562482996626694026">"Mostrar atalhos"</string>
<string name="group_system_go_back" msgid="2730322046244918816">"Voltar"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"acessar o dispositivo"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use a impressão digital para abrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticação obrigatória. Toque no sensor de impressão digital para autenticar."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Chamada em andamento"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Dados móveis"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Conectado"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Temporariamente conectado"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"App atual"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Acessibilidade"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Atalhos do teclado"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizar atalhos de teclado"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalizar atalhos"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Remover atalho?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Redefinir para o padrão?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pressione a tecla para atribuir o atalho"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Essa combinação de teclas já está em uso. Tente outra tecla."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Não é possível definir o atalho."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Adicionar atalho"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Excluir atalho"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navegue usando o teclado"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprenda atalhos do teclado"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navegue usando o touchpad"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index a9de96156d5b..303a2808d552 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satélite, boa ligação"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, ligação disponível"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satélite SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Chamadas de emergência ou SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"sem sinal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"1 barra"</string>
@@ -883,7 +884,7 @@
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Abrir definições"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Abrir Assistente"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Ecrã de bloqueio"</string>
- <string name="group_system_quick_memo" msgid="3764560265935722903">"Tire notas"</string>
+ <string name="group_system_quick_memo" msgid="3764560265935722903">"Tirar notas"</string>
<string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Execução de várias tarefas em simultâneo"</string>
<string name="system_multitasking_rhs" msgid="8779289852395243004">"Use o ecrã dividido com a app à direita"</string>
<string name="system_multitasking_lhs" msgid="7348595296208696452">"Use o ecrã dividido com a app à esquerda"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"entrar no dispositivo"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Utilize a impressão digital para abrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticação necessária. Toque no sensor de impressões digitais para autenticar."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Chamada em curso"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Dados móveis"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Ligado"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Ligado temporariamente"</string>
@@ -1430,14 +1430,14 @@
<string name="shortcut_helper_category_system" msgid="462110876978937359">"Sistema"</string>
<string name="shortcut_helper_category_system_controls" msgid="3153344561395751020">"Controlos do sistema"</string>
<string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Apps do sistema"</string>
- <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Execução de várias tarefas em simultâneo"</string>
+ <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string>
<string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Ecrã dividido"</string>
<string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string>
<string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Atalhos de apps"</string>
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"App atual"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Acessibilidade"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Atalhos de teclado"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalize os atalhos de teclado"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalize os atalhos"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Remover atalho?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Repor para a predefinição?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Prima a tecla para atribuir o atalho"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"A combinação de teclas já está a ser usada. Experimente outra tecla."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Não é possível definir o atalho."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Adicionar atalho"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Eliminar atalho"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navegue com o teclado"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprenda atalhos de teclado"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navegue com o touchpad"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index e7bcaa25e7fb..ead72a21e432 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -688,7 +688,7 @@
<string name="stream_system" msgid="7663148785370565134">"Sistema"</string>
<string name="stream_ring" msgid="7550670036738697526">"Toques"</string>
<string name="stream_music" msgid="2188224742361847580">"Mídia"</string>
- <string name="stream_alarm" msgid="16058075093011694">"Alarme"</string>
+ <string name="stream_alarm" msgid="16058075093011694">"Alarmes"</string>
<string name="stream_notification" msgid="7930294049046243939">"Notificações"</string>
<string name="stream_bluetooth_sco" msgid="6234562365528664331">"Bluetooth"</string>
<string name="stream_dtmf" msgid="7322536356554673067">"Multifrequência de dois tons"</string>
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satélite, conexão boa"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, conexão disponível"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via satélite"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Chamadas de emergência ou SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"sem sinal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"uma barra"</string>
@@ -871,7 +872,7 @@
<string name="keyboard_shortcut_a11y_filter_input" msgid="4589316004510335529">"Mostrando atalhos de entrada"</string>
<string name="keyboard_shortcut_a11y_filter_open_apps" msgid="6175417687221004059">"Mostrando atalhos que abrem apps"</string>
<string name="keyboard_shortcut_a11y_filter_current_app" msgid="7944592357493737911">"Mostrando atalhos do app atual"</string>
- <string name="group_system_access_notification_shade" msgid="1619028907006553677">"Mostrar as notificações"</string>
+ <string name="group_system_access_notification_shade" msgid="1619028907006553677">"Ver notificações"</string>
<string name="group_system_full_screenshot" msgid="5742204844232667785">"Fazer uma captura de tela"</string>
<string name="group_system_access_system_app_shortcuts" msgid="8562482996626694026">"Mostrar atalhos"</string>
<string name="group_system_go_back" msgid="2730322046244918816">"Voltar"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"acessar o dispositivo"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use a impressão digital para abrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticação obrigatória. Toque no sensor de impressão digital para autenticar."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Chamada em andamento"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Dados móveis"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Conectado"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Temporariamente conectado"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"App atual"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Acessibilidade"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Atalhos do teclado"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizar atalhos de teclado"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalizar atalhos"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Remover atalho?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Redefinir para o padrão?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pressione a tecla para atribuir o atalho"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Essa combinação de teclas já está em uso. Tente outra tecla."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Não é possível definir o atalho."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Adicionar atalho"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Excluir atalho"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navegue usando o teclado"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprenda atalhos do teclado"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navegue usando o touchpad"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 7fb1169af6f9..afd18f12cbf5 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, conexiune bună"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, conexiune disponibilă"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS prin satelit"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Apeluri de urgență sau SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"fără semnal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"o bară"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"Accesează dispozitivul"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Folosește amprenta ca să deschizi"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentificare obligatorie. Atinge senzorul de amprentă pentru a te autentifica."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Apel în desfășurare"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Date mobile"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Conectat"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Conectat temporar"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aplicația actuală"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accesibilitate"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Comenzi rapide de la tastatură"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizează comenzile rapide de la tastatură"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalizează comenzile rapide"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Elimini comanda rapidă?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Resetezi la valorile prestabilite?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Apasă tasta pentru a atribui comanda rapidă"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Combinația de taste este deja folosită. Încearcă altă tastă."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Comanda rapidă nu poate fi setată."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Adaugă o comandă rapidă"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Șterge comanda rapidă"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navighează folosind tastatura"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Învață comenzile rapide de la tastatură"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navighează folosind touchpadul"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 448c2457efe1..10dc51d71683 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Спутниковая связь, хорошее качество соединения"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Доступно соединение по спутниковой связи"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Спутниковый SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Экстренные вызовы или спутниковый SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"нет сигнала"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"одно деление"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"указать устройство"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Используйте отпечаток пальца для входа."</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Требуется аутентификация. Приложите палец к сканеру отпечатков."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Текущий вызов"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобильный интернет"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Подключено"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Временное подключение"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Это приложение"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Специальные возможности"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Сочетания клавиш"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Настройки сочетаний клавиш"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Настройки сочетаний клавиш"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Удалить сочетание клавиш?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Сбросить настройки?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Нажмите клавишу, чтобы назначить сочетание клавиш."</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Это сочетание клавиш уже используется. Попробуйте другое."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Это сочетание клавиш выбрать нельзя."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Добавить сочетание клавиш"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Удалить сочетание клавиш"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Навигация с помощью клавиатуры"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Узнайте о сочетаниях клавиш."</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Навигация с помощью сенсорной панели"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index d5c90b566ad6..5a7a6a377527 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"චන්ද්‍රිකාව, හොඳ සම්බන්ධතාවයක්"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"චන්ද්‍රිකාව, සම්බන්ධතාවය තිබේ"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"චන්ද්‍රිකා SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"හදිසි ඇමතුම් හෝ SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"සංඥාව නැත"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"තීරු එකක්"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"උපාංගය ඇතුළු කරන්න"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"විවෘත කිරීමට ඇඟිලි සලකුණ භාවිත කරන්න"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"සත්‍යාපනය අවශ්‍යයි. සත්‍යාපනය කිරීමට ඇඟිලි සලකුණු සංවේදකය ස්පර්ශ කරන්න."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"කර ගෙන යන ඇමතුම"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"ජංගම දත්ත"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"සම්බන්ධයි"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"තාවකාලිකව සම්බන්ධ කළා"</string>
@@ -1437,7 +1437,8 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"වත්මන් යෙදුම"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ප්‍රවේශ්‍යතාව"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"යතුරු පුවරු කෙටි මං"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"යතුරුපුවරු කෙටිමං අභිරුචිකරණය කරන්න"</string>
+ <!-- no translation found for shortcut_helper_customize_mode_title (8327297960035006036) -->
+ <skip />
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"කෙටිමඟ ඉවත් කරන්න ද?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"පෙරනිමියට යළි සකසන්න ද?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"කෙටිමඟ පැවරීමට යතුර ඔබන්න"</string>
@@ -1465,6 +1466,10 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"යතුරු සංයෝජනය දැනටමත් භාවිත වේ. වෙනත් යතුරක් උත්සාහ කරන්න."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"කෙටිමඟ සැකසිය නොහැක."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <!-- no translation found for shortcut_helper_add_shortcut_button_label (7655779534665954910) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_delete_shortcut_button_label (3148773472696137052) -->
+ <skip />
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ඔබේ යතුරු පුවරුව භාවිතයෙන් සංචාලනය කරන්න"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"යතුරුපුවරු කෙටිමං ඉගෙන ගන්න"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ඔබේ ස්පර්ශ පෑඩ් භාවිතයෙන් සංචාලනය කරන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index af84fd19bb0c..d2d9cdeed413 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, dobrá kvalita pripojenia"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, pripojenie je k dispozícii"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Pomoc cez satelit"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Tiesňové volania alebo pomoc v tiesni"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"žiadny signál"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"jedna čiarka"</string>
@@ -881,7 +882,7 @@
<string name="group_system_cycle_back" msgid="8194102916946802902">"Cyklické prechádzanie dozadu nedávnymi aplikáciami"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Otvorenie zoznamu aplikácií"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Otvorenie nastavení"</string>
- <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Otvoriť asistenta"</string>
+ <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Otvorenie Asistenta"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Uzamknutie obrazovky"</string>
<string name="group_system_quick_memo" msgid="3764560265935722903">"Napísanie poznámky"</string>
<string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"vstúpte do zariadenia"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorte odtlačkom prsta"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Vyžaduje sa overenie. Dotknite sa senzora odtlačkov prstov."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Prebiehajúci hovor"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilné dáta"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Pripojené"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Dočasne pripojené"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktuálna aplikácia"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Dostupnosť"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Klávesové skratky"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prispôsobenie klávesových skratiek"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Prispôsobenie skratiek"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Chcete skratku odstrániť?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Chcete resetovať na predvolené nastavenie?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Stlačením klávesa priraďte skratku"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Kombinácia klávesov sa už používa. Skúste iný kláves."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Skratku nie je možné nastaviť."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Pridať skratku"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Odstrániť skratku"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Pohybujte sa v systéme pomocou klávesnice"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Naučte sa klávesové skratky"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Pohybujte sa v systéme pomocou touchpadu"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 1242774768b3..c473962ca1ba 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, dobra povezava"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, povezava je na voljo"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS prek satelita"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Klici v sili ali SOS prek satelita"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"ni signala"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"ena črtica"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"vstop v napravo"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Odprite s prstnim odtisom"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Zahtevano je preverjanje pristnosti. Za preverjanje pristnosti se dotaknite tipala prstnih odtisov."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Aktivni klic"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Prenos podatkov v mobilnem omrežju"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Začasno vzpostavljena povezava"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Trenutna aplikacija"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Dostopnost"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Bližnjične tipke"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prilagajanje bližnjičnih tipk"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Prilagajanje bližnjic"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Želite odstraniti bližnjico?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Želite ponastaviti na privzete bližnjice?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pritisnite tipko za dodelitev bližnjice"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Kombinacija tipk je že v uporabi. Poskusite z drugo tipko."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Bližnjice ni mogoče nastaviti."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Dodajanje bližnjice"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Izbris bližnjice"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Krmarjenje s tipkovnico"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Učenje bližnjičnih tipk"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Krmarjenje s sledilno ploščico"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index c3d13539e1f9..3c7d05b2e318 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Sateliti. Lidhje e mirë"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Sateliti. Ofrohet lidhje"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS satelitor"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Telefonatat e urgjencës ose SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"nuk ka sinjal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"një vijë"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"për të hyrë në pajisje"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Përdor gjurmën e gishtit për ta hapur"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Kërkohet vërtetimi. Prek sensorin e gjurmës së gishtit për t\'u vërtetuar."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Telefonatë në vazhdim"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Të dhënat celulare"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Lidhur"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Lidhur përkohësisht"</string>
@@ -1437,7 +1437,8 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aplikacioni aktual"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Qasshmëria"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Shkurtoret e tastierës"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizo shkurtoret e tastierës"</string>
+ <!-- no translation found for shortcut_helper_customize_mode_title (8327297960035006036) -->
+ <skip />
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Të hiqet shkurtorja?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Të rivendosen përsëri te parazgjedhjet?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Shtyp tastin për të caktuar shkurtoren"</string>
@@ -1465,6 +1466,10 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Kombinimi i tasteve është tashmë në përdorim. Provo një tast tjetër."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Shkurtorja nuk mund të caktohet."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <!-- no translation found for shortcut_helper_add_shortcut_button_label (7655779534665954910) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_delete_shortcut_button_label (3148773472696137052) -->
+ <skip />
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigo duke përdorur tastierën tënde"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Mëso shkurtoret e tastierës"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigo duke përdorur bllokun me prekje"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 344b012c2c80..b7ddd4d7c6d2 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Сателит, веза је добра"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Сателит, веза је доступна"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Хитна помоћ преко сателита"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Хитни позиви или хитна помоћ"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"нема сигнала"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"једна црта"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"унесите уређај"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Отворите помоћу отиска прста"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Потребна је потврда идентитета. Додирните сензор за отисак прста да бисте потврдили идентитет."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Позив је у току"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилни подаци"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Повезано"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Привремено повезано"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Актуелна апликација"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Приступачност"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Тастерске пречице"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Прилагодите тастерске пречице"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Прилагодите пречице"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Желите да уклоните пречицу?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Желите да ресетујете на подразумевано?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Притисните тастер да бисте доделили пречицу"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Комбинација тастера се већ користи. Пробајте са другим тастером."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Подешавање пречице није успело."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Додајте пречицу"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Избришите пречицу"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Крећите се помоћу тастатуре"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Сазнајте више о тастерским пречицама"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Крећите се помоћу тачпеда"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 4d862d9842a8..2d2a94d4e7b2 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellit, bra anslutning"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellit, anslutning tillgänglig"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS-larm via satellit"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Nödsamtal eller SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"ingen signal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"en stapel"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ange enhet"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Öppna med fingeravtryck"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentisering krävs. Identifiera dig genom att trycka på fingeravtryckssensorn."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Pågående samtal"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobildata"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Ansluten"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Tillfälligt ansluten"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktuell app"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Tillgänglighet"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Kortkommandon"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Anpassa kortkommandon"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Anpassa kortkommandon"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Vill du ta bort kortkommandot?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Vill du återställa till standardinställningarna?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Tryck på tangenten för att tilldela ett kortkommando"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Tangentkombinationen används redan. Testa en annan tangent."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Det går inte att ställa in kortkommandot."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Lägg till genväg"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Radera genväg"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigera med tangentbordet"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Lär dig kortkommandon"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigera med styrplattan"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 731765437ced..424434d182a7 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Setilaiti, muunganisho thabiti"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Setilaiti, muunganisho unapatikana"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Msaada kupitia Setilaiti"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Simu za dharura"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"hakuna mtandao"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"upau mmoja"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"weka kifaa"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Tumia alama ya kidole kufungua"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Uthibitishaji unahitajika. Gusa kitambua alama ya kidole ili uthibitishe."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Simu inayoendelea"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Data ya mtandao wa simu"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Imeunganishwa"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Imeunganishwa kwa muda"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Programu Inayotumika Sasa"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Ufikivu"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Mikato ya kibodi"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Weka mapendeleo ya mikato ya kibodi"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Kuweka mapendeleo ya njia za mkato"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Ungependa kuondoa njia ya mkato?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Ungependa kurejesha njia za mkato chaguomsingi?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Bonyeza kitufe ukabidhi njia ya mkato"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Tayari unatumia mchanganyiko wa vitufe. Jaribu kitufe kingine."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Haiwezi kuweka njia ya mkato."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Weka njia ya mkato"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Futa njia ya mkato"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Kusogeza kwa kutumia kibodi yako"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Fahamu kuhusu mikato ya kibodi"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Kusogeza kwa kutumia padi yako ya kugusa"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 5a7defae136f..cb340789345e 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"சாட்டிலைட், நிலையான இணைப்பு"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"சாட்டிலைட், இணைப்பு கிடைக்கிறது"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"சாட்டிலைட் SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"அவசர அழைப்புகள் அல்லது SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"சிக்னல் இல்லை"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"ஒரு கோடு"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"சாதனத்தைத் திற"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"கைரேகையைப் பயன்படுத்தி திறந்திடுங்கள்"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"அங்கீகாரம் தேவை. கைரேகை சென்சாரைத் தொட்டு அங்கீகரியுங்கள்."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"செயலில் உள்ள அழைப்பு"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"மொபைல் டேட்டா"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"இணைக்கப்பட்டது"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"தற்காலிகமாக இணைக்கப்பட்டுள்ளது"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"தற்போதைய ஆப்ஸ்"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"மாற்றுத்திறன் வசதி"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"கீபோர்டு ஷார்ட்கட்கள்"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"கீபோர்டு ஷார்ட்கட்களைப் பிரத்தியேகப்படுத்துதல்"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"ஷார்ட்கட்களைப் பிரத்தியேகமாக்குதல்"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"ஷார்ட்கட்டை அகற்றவா?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"மீண்டும் இயல்புநிலைக்கு மீட்டமைக்கவா?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"ஷார்ட்கட்டை அமைக்க பட்டனை அழுத்துங்கள்"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"பட்டன் சேர்க்கை ஏற்கெனவே பயன்பாட்டில் உள்ளது. வேறொரு பட்டனைப் பயன்படுத்திப் பார்க்கவும்."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"ஷார்ட்கட்டை அமைக்க முடியாது."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"ஷார்ட்கட்டைச் சேர்க்கும்"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"ஷார்ட்கட்டை அகற்றும்"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"கீபோர்டைப் பயன்படுத்திச் செல்லுதல்"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"கீபோர்டு ஷார்ட்கட்கள் குறித்துத் தெரிந்துகொள்ளுங்கள்"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"டச்பேடைப் பயன்படுத்திச் செல்லுதல்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 1be6ce61a399..8dac7651ae49 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"శాటిలైట్, కనెక్షన్ బాగుంది"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"శాటిలైట్, కనెక్షన్ అందుబాటులో ఉంది"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"ఎమర్జెన్సీ శాటిలైట్ సహాయం"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"ఎమర్జెన్సీ కాల్స్ లేదా SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"సిగ్నల్ లేదు"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"సిగ్నల్ ఒక బార్ ఉంది"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"పరికరాన్ని ఎంటర్ చేయండి"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"తెరవడానికి వేలిముద్రను ఉపయోగించండి"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ప్రామాణీకరణ అవసరం. ప్రామాణీకరించడానికి వేలిముద్ర సెన్సార్‌ను తాకండి."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"కాల్ కొనసాగుతోంది"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"మొబైల్ డేటా"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"కనెక్ట్ చేయబడింది"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"తాత్కాలికంగా కనెక్ట్ చేయబడింది"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"ప్రస్తుత యాప్"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"యాక్సెసిబిలిటీ"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"కీబోర్డ్ షార్ట్‌కట్‌లు"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"కీబోర్డ్ షార్ట్‌కట్‌లను అనుకూలంగా మార్చండి"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"షార్ట్‌కట్‌లను అనుకూలంగా మార్చండి"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"షార్ట్‌కట్‌ను తీసివేయాలా?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"తిరిగి ఆటోమేటిక్ సెట్టింగ్‌కు రీసెట్ చేయాలా?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"షార్ట్‌కట్‌ను కేటాయించడానికి కీని నొక్కండి"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"కీ కాంబినేషన్ ఇప్పటికే వినియోగంలో ఉంది. వేరొక కీని ట్రై చేయండి."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"షార్ట్‌కట్‌ను సెట్ చేయడం సాధ్యం కాదు."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"షార్ట్‌కట్‌ను జోడించండి"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"షార్ట్‌కట్‌ను తొలగించండి"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"మీ కీబోర్డ్ ఉపయోగించి నావిగేట్ చేయండి"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"కీబోర్డ్ షార్ట్‌కట్‌ల గురించి తెలుసుకోండి"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"మీ టచ్‌ప్యాడ్‌ను ఉపయోగించి నావిగేట్ చేయండి"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 3770addf98e3..cd111fd54d02 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ดาวเทียม, การเชื่อมต่อดี"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ดาวเทียม, การเชื่อมต่อที่พร้อมใช้งาน"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS ดาวเทียม"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"การโทรฉุกเฉินหรือ SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"ไม่มีสัญญาณ"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"1 ขีด"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"เข้าถึงอุปกรณ์"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ใช้ลายนิ้วมือเพื่อเปิด"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ต้องมีการตรวจสอบสิทธิ์ แตะเซ็นเซอร์ลายนิ้วมือเพื่อตรวจสอบสิทธิ์"</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"สายที่สนทนาอยู่"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"อินเทอร์เน็ตมือถือ"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"เชื่อมต่อแล้ว"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"เชื่อมต่อแล้วชั่วคราว"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"แอปปัจจุบัน"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"การช่วยเหลือพิเศษ"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"แป้นพิมพ์ลัด"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"ปรับแต่งแป้นพิมพ์ลัด"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"ปรับแต่งแป้นพิมพ์ลัด"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"นำแป้นพิมพ์ลัดออกใช่ไหม"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"รีเซ็ตกลับเป็นค่าเริ่มต้นไหม"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"กดแป้นเพื่อกำหนดแป้นพิมพ์ลัด"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"มีการใช้แป้นที่กดร่วมกันนี้แล้ว โปรดลองใช้แป้นอื่น"</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"ตั้งค่าแป้นพิมพ์ลัดไม่ได้"</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"เพิ่มทางลัด"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"ลบทางลัด"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ไปยังส่วนต่างๆ โดยใช้แป้นพิมพ์"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ดูข้อมูลเกี่ยวกับแป้นพิมพ์ลัด"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ไปยังส่วนต่างๆ โดยใช้ทัชแพด"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index d28915eccb73..3c5448e20664 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellite, malakas ang koneksyon"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellite, may koneksyon"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Mga emergency na tawag o SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"walang signal"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"isang bar"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ilagay ang device"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gamitin ang fingerprint para buksan"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Kailangan ng pag-authenticate. Pindutin ang sensor para sa fingerprint para mag-authenticate."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Kasalukuyang tawag"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Nakakonekta"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Pansamantalang nakakonekta"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Kasalukuyang App"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibility"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Mga keyboard shortcut"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"I-customize ang mga keyboard shortcut"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"I-customize ang mga shortcut"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Alisin ang shortcut?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"I-reset pabalik sa default?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pindutin ang key para magtalaga ng shortcut"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Ginagamit na ang kumbinasyon ng key. Sumubok ng ibang key."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Hindi maitakda ang shortcut."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Maglagay ng shortcut"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Mag-delete ng shortcut"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Mag-navigate gamit ang iyong keyboard"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Matuto ng mga keyboard shortcut"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Mag-navigate gamit ang iyong touchpad"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 29a5763385bd..61ed4e54209b 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Uydu, bağlantı güçlü"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Uydu, bağlantı mevcut"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Acil Uydu Bağlantısı"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Acil durum aramaları veya acil yardım"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"sinyal yok"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"tek çubuk"</string>
@@ -882,7 +883,7 @@
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Uygulama listesini aç"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Ayarları aç"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Asistan\'ı aç"</string>
- <string name="group_system_lock_screen" msgid="7391191300363416543">"Kilit ekranı"</string>
+ <string name="group_system_lock_screen" msgid="7391191300363416543">"Ekranı kilitle"</string>
<string name="group_system_quick_memo" msgid="3764560265935722903">"Not al"</string>
<string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Çoklu görev"</string>
<string name="system_multitasking_rhs" msgid="8779289852395243004">"Sağdaki uygulamayla birlikte bölünmüş ekranı kullan"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"cihaz girin"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Açmak için parmak izi kullanın"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Kimlik doğrulaması gerekiyor. Kimlik doğrulaması için parmak izi sensörüne dokunun."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Devam eden arama"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobil veri"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Bağlı"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Geçici olarak bağlandı"</string>
@@ -1437,13 +1437,13 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Mevcut Uygulama"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Erişilebilirlik"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Klavye kısayolları"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Klavye kısayollarını özelleştirin"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Kısayolları özelleştirin"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Kısayol kaldırılsın mı?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Varsayılan kısayollara sıfırlansın mı?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Kısayol atamak için tuşa basın"</string>
<string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Bu işlem, özel kısayolunuzu kalıcı olarak siler."</string>
<string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Bu işlem, tüm özel kısayollarınızı kalıcı olarak siler."</string>
- <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Arama kısayolları"</string>
+ <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Kısayollarda ara"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Arama sonucu yok"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Daralt simgesi"</string>
<string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"İşlem veya Meta tuşu simgesi"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Tuş kombinasyonu zaten kullanılıyor. Başka bir tuş deneyin."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Kısayol ayarlanamıyor."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Kısayol ekle"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Kısayolu sil"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Klavyenizi kullanarak gezinin"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Klavye kısayollarını öğrenin"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Dokunmatik alanınızı kullanarak gezinin"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index ea839cc9f96a..778b25bf4651 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Хороше з’єднання із супутником"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Доступне з’єднання із супутником"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Супутниковий сигнал SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Екстрені виклики або сигнал SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"немає сигналу"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"одна смужка сигналу"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"відкрити пристрій"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Щоб відкрити, використайте відбиток пальця"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Пройдіть автентифікацію. Для цього торкніться сканера відбитків пальців."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Поточний виклик"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобільний трафік"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Підключено"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Тимчасово з’єднано"</string>
@@ -1437,7 +1437,8 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Поточний додаток"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Доступність"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Комбінації клавіш"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Налаштуйте комбінації клавіш"</string>
+ <!-- no translation found for shortcut_helper_customize_mode_title (8327297960035006036) -->
+ <skip />
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Видалити комбінацію клавіш?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Відновити комбінації клавіш за умовчанням?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Натисніть клавішу, щоб призначити комбінацію клавіш"</string>
@@ -1465,6 +1466,10 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Комбінація клавіш уже використовується. Спробуйте іншу клавішу."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Не вдалося встановити комбінацію клавіш."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <!-- no translation found for shortcut_helper_add_shortcut_button_label (7655779534665954910) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_delete_shortcut_button_label (3148773472696137052) -->
+ <skip />
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Навігація за допомогою клавіатури"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Дізнайтеся більше про комбінації клавіш"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Навігація за допомогою сенсорної панелі"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 63fa93d74ea9..2f3e6f4bcfe8 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"سیٹلائٹ، کنکشن اچھا ہے"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"سیٹلائٹ، کنکشن دستیاب ہے"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"‏سیٹلائٹ SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"‏ایمرجنسی کالز یا SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>، <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>۔"</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"کوئی سگنل نہیں"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"ایک بار"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"آلہ درج کریں"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"کھولنے کے لیے فنگر پرنٹ کا استعمال کریں"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"توثیق مطلوب ہے۔ توثیق کرنے کے لیے فنگر پرنٹ سینسر کو ٹچ کریں۔"</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"جاری کال"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"موبائل ڈیٹا"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"منسلک ہے"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"عارضی طور پر منسلک ہے"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"موجودہ ایپ"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ایکسیسبیلٹی"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"کی بورڈ شارٹ کٹس"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"کی بورڈ شارٹ کٹس کو حسب ضرورت بنائیں"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"شارٹ کٹس کو حسب ضرورت بنائیں"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"شارٹ کٹ ہٹائیں؟"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ڈیفالٹ پر واپس ری سیٹ کریں؟"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"شارٹ کٹ تفویض کرنے کے لیے کلید کو دبائیں"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"کلیدی مجموعہ پہلے سے استعمال میں ہے۔ دوسری کلید آزمائیں۔"</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"شارٹ کٹ سیٹ نہیں کیا جا سکتا۔"</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"شارٹ کٹ شامل کریں"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"شارٹ کٹ حذف کریں"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"اپنے کی بورڈ کا استعمال کر کے نیویگیٹ کریں"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"کی بورڈ شارٹ کٹس جانیں"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"اپنے ٹچ پیڈ کا استعمال کر کے نیویگیٹ کریں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index a20f42d88c7c..23137bd9898c 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Sputnik, aloqa sifati yaxshi"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Sputnik, aloqa mavjud"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Sputnik SOS"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Favqulodda chaqiruvlar yoki SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"signal yoʻq"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"bitta ustun"</string>
@@ -871,12 +872,12 @@
<string name="keyboard_shortcut_a11y_filter_input" msgid="4589316004510335529">"Kirish bilan bogʻliq tezkor tugmalarni koʻrsatiladi"</string>
<string name="keyboard_shortcut_a11y_filter_open_apps" msgid="6175417687221004059">"Ilovalarni ochuvchi tezkor tugmalar koʻrsatiladi"</string>
<string name="keyboard_shortcut_a11y_filter_current_app" msgid="7944592357493737911">"Joriy ilova uchun tezkor tugmalar koʻrsatiladi"</string>
- <string name="group_system_access_notification_shade" msgid="1619028907006553677">"Bildirishnomalarni ochish"</string>
+ <string name="group_system_access_notification_shade" msgid="1619028907006553677">"Bildirishnomalarni koʻrish"</string>
<string name="group_system_full_screenshot" msgid="5742204844232667785">"Skrinshot olish"</string>
<string name="group_system_access_system_app_shortcuts" msgid="8562482996626694026">"Yorliqlarni ochish"</string>
<string name="group_system_go_back" msgid="2730322046244918816">"Orqaga"</string>
<string name="group_system_access_home_screen" msgid="4130366993484706483">"Bosh ekranni ochish"</string>
- <string name="group_system_overview_open_apps" msgid="5659958952937994104">"Oxirgi ilovalarni ochish"</string>
+ <string name="group_system_overview_open_apps" msgid="5659958952937994104">"Oxirgi ilovalarni koʻrish"</string>
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Oxirgi ilovalarni oldinga varaqlash"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Oxirgi ilovalarni orqaga varaqlash"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Ilovalar roʻyxatini ochish"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"qurilmani ochish"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Ochish uchun barmoq izidan foydalaning"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Haqiqiylikni tekshirish talab etiladi. Autentifikatsiya uchun barmoq izi skaneriga tegining."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Joriy chaqiruv"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobil internet"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Ulangan"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Vaqtincha ulangan"</string>
@@ -1437,7 +1437,8 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Joriy ilova"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Qulayliklar"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Tezkor tugmalar"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Tezkor tugmalarni moslash"</string>
+ <!-- no translation found for shortcut_helper_customize_mode_title (8327297960035006036) -->
+ <skip />
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Tezkor tugma olib tashlansinmi?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Asliga qaytarilsinmi?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Tezkor tugma sozlash uchun tugmani bosing"</string>
@@ -1465,6 +1466,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Bu tugmalar birikmasi band. Boshqasini ishlating."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Buyruq sozlanmadi."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Yorliq yaratish"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Yorliqni oʻchirish"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Klaviatura yordamida kezing"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Tezkor tugmalar haqida"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Sensorli panel yordamida kezing"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 2a8fa4c9cc7b..3b4b132698f3 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Kết nối vệ tinh tốt"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Hiện có kết nối vệ tinh"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Liên lạc khẩn cấp qua vệ tinh"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Cuộc gọi khẩn cấp hoặc SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"không có tín hiệu"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"1 vạch"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"truy cập thiết bị"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Dùng vân tay để mở"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Bạn cần phải xác thực. Hãy chạm vào cảm biến vân tay để xác thực."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Cuộc gọi đang diễn ra"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Dữ liệu di động"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Đã kết nối"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Tạm thời có kết nối"</string>
@@ -1433,11 +1433,11 @@
<string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Đa nhiệm"</string>
<string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Chia đôi màn hình"</string>
<string name="shortcut_helper_category_input" msgid="8674018654124839566">"Phương thức nhập"</string>
- <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Lối tắt ứng dụng"</string>
+ <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Phím tắt cho ứng dụng"</string>
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Ứng dụng hiện tại"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Hỗ trợ tiếp cận"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Phím tắt"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Tuỳ chỉnh phím tắt"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Tuỳ chỉnh phím tắt"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Xoá phím tắt?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Đặt lại về phím tắt mặc định?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Nhấn phím để chỉ định phím tắt"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Tổ hợp phím đã được sử dụng. Hãy thử một phím khác."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Không đặt được lối tắt."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Thêm phím tắt"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Xoá phím tắt"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Di chuyển bằng bàn phím"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Tìm hiểu về phím tắt"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Di chuyển bằng 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 8f0b2f11da93..e66048e8022a 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"卫星,连接质量良好"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"卫星,可连接"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"卫星紧急呼救"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"紧急呼叫或紧急求救"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>,<xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>。"</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"无信号"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"信号强度为一格"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"进入设备"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"使用指纹即可打开"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"需要进行身份验证。请轻触指纹传感器以验证身份。"</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"正在通话"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"移动数据网络"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"已连接"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"已暂时连接"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"当前应用"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"无障碍功能"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"键盘快捷键"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"自定义键盘快捷键"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"自定义快捷方式"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"要移除快捷键吗?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"要重置为默认快捷键吗?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"按下按键即可指定快捷键"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"按键组合已被使用,请尝试使用其他按键。"</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"无法设置快捷方式。"</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"添加快捷方式"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"删除快捷方式"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"使用键盘导航"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"了解键盘快捷键"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"使用触控板导航"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index afae659eb972..f9631f267948 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"衛星,連線質素好"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"衛星,可以連線"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"緊急衛星連接"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"緊急電話或 SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>,<xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>。"</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"無訊號"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"一格"</string>
@@ -877,8 +878,8 @@
<string name="group_system_go_back" msgid="2730322046244918816">"返回"</string>
<string name="group_system_access_home_screen" msgid="4130366993484706483">"前往主畫面"</string>
<string name="group_system_overview_open_apps" msgid="5659958952937994104">"查看最近使用的應用程式"</string>
- <string name="group_system_cycle_forward" msgid="5478663965957647805">"輪流切換最近使用的應用程式 (向前)"</string>
- <string name="group_system_cycle_back" msgid="8194102916946802902">"輪流切換最近使用的應用程式 (向後)"</string>
+ <string name="group_system_cycle_forward" msgid="5478663965957647805">"順序查看最近使用的應用程式"</string>
+ <string name="group_system_cycle_back" msgid="8194102916946802902">"倒序查看最近使用的應用程式"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"開啟應用程式清單"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"開啟設定"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"開啟「Google 助理」"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"進入裝置"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"使用指紋即可開啟"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"需要驗證。掂一下指紋感應器就可以驗證。"</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"通話中"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"流動數據"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"已連線"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"已暫時連線"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"目前的應用程式"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"無障礙功能"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"鍵盤快速鍵"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"自訂鍵盤快速鍵"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"自訂快速鍵"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"要移除快速鍵嗎?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"要重設至預設捷徑嗎?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"按鍵即可指派快速鍵"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"此按鍵組合已在使用,請改用其他按鍵。"</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"無法設定快速鍵。"</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"新增捷徑"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"刪除捷徑"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"使用鍵盤導覽"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"瞭解鍵盤快速鍵"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"使用觸控板導覽"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index f52e906add3e..4394dd9a0bd7 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -759,7 +759,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"衛星,連線品質良好"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"衛星,可連線"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"緊急衛星連線"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"緊急電話或緊急求救"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>,<xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>。"</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"沒有訊號"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"訊號強度一格"</string>
@@ -1289,8 +1290,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"進入裝置"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"使用指紋即可開啟"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"需要驗證。輕觸指紋感應器即可進行驗證。"</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"通話中"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"行動數據"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"已連線"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"已暫時建立連線"</string>
@@ -1437,7 +1437,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"目前的應用程式"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"無障礙"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"鍵盤快速鍵"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"自訂鍵盤快速鍵"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"自訂快速鍵"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"要移除快速鍵嗎?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"要重設為預設值嗎?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"按下按鍵即可指派快速鍵"</string>
@@ -1465,6 +1465,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"按鍵組合重複,請改用其他按鍵。"</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"無法設定捷徑。"</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"新增快速鍵"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"刪除快速鍵"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"使用鍵盤操作"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"學習鍵盤快速鍵"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"使用觸控板操作"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index a63167ed8ac2..f7f4bcfcdc83 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -761,7 +761,8 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Isethelayithi, uxhumano oluhle"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Isethelayithi, uxhumano luyatholakala"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"Isethelayithi yokuxhumana ngezimo eziphuthumayo"</string>
- <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Ikholi ephuthumayo noma i-SOS"</string>
+ <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) -->
+ <skip />
<string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string>
<string name="accessibility_no_signal" msgid="7052827511409250167">"ayikho isignali"</string>
<string name="accessibility_one_bar" msgid="5342012847647834506">"ibha eyodwa"</string>
@@ -1291,8 +1292,7 @@
<string name="accessibility_enter_hint" msgid="2617864063504824834">"faka idivayisi"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Sebenzisa izigxivizo zeminwe ukuvula"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Ukufakazela ubuqiniso budingekile. Thinta inzwa yezigxivizo zeminwe ukuze uqinisekise."</string>
- <!-- no translation found for ongoing_call_content_description (6394763878322348560) -->
- <skip />
+ <string name="ongoing_call_content_description" msgid="6394763878322348560">"Ikholi eqhubekayo"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Idatha yeselula"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Ixhunyiwe"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Ixhume okwesikhashana"</string>
@@ -1439,7 +1439,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"I-App yamanje"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Ukufinyeleleka"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"Izinqamuleli zekhibhodi"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Hlela izinqamuleli zekhibhodi ngendlela oyifisayo"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Qamba ngokwabahlinzekelwayo izinqamuleli"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Susa isinqamuleli?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Setha kabusha ubuyele kokuzenzakalelayo?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Cindezela ukhiye ukuze unikeze isinqamuleli"</string>
@@ -1467,6 +1467,8 @@
<string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Inhlanganisela yokhiye isiyasetshenziswa kakade. Zama omunye ukhiye."</string>
<string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Isinqamuleli asikwazi ukusethwa."</string>
<string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string>
+ <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Faka isinqamuleli"</string>
+ <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Sula isinqamuleli"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Funa usebenzisa ikhibhodi yakho"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Funda izinqamuleli zamakhibhodi"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Funa usebenzisa iphedi yokuthinta"</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2ffa3d19e161..f9904e336f24 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -254,9 +254,6 @@
<!-- Reference width used when validating notification layouts -->
<dimen name="notification_validation_reference_width">320dp</dimen>
- <!-- Increased height of a small notification in the status bar -->
- <dimen name="notification_min_height_increased">146dp</dimen>
-
<!-- Height of a small notification in the status bar which was used before android N -->
<dimen name="notification_min_height_legacy">64dp</dimen>
@@ -281,9 +278,6 @@
<!-- Height of a heads up notification in the status bar -->
<dimen name="notification_max_heads_up_height">136dp</dimen>
- <!-- Height of a heads up notification in the status bar -->
- <dimen name="notification_max_heads_up_height_increased">188dp</dimen>
-
<!-- Side padding on the side of notifications -->
<dimen name="notification_side_paddings">16dp</dimen>
@@ -1128,6 +1122,7 @@
<dimen name="smart_reply_button_corner_radius">8dp</dimen>
<dimen name="smart_action_button_icon_size">18dp</dimen>
<dimen name="smart_action_button_icon_padding">8dp</dimen>
+ <dimen name="smart_action_button_outline_stroke_width">2dp</dimen>
<!-- A reasonable upper bound for the height of the smart reply button. The measuring code
needs to start with a guess for the maximum size. Currently two-line smart reply buttons
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a8ee60973586..f2c648cb3ab0 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2250,8 +2250,6 @@
<string name="keyboard_shortcut_group_system_notifications">Notifications</string>
<!-- User visible title for the keyboard shortcut that triggers the keyboard shortcuts helper. -->
<string name="keyboard_shortcut_group_system_shortcuts_helper">Keyboard Shortcuts</string>
- <!-- User visible title for the keyboard shortcut that switches to the next hardware keyboard layout. -->
- <string name="keyboard_shortcut_group_system_switch_input">Switch keyboard layout</string>
<!-- User visible string that joins different shortcuts in a list, e.g. shortcut1 "or" shortcut2 "or" ... -->
<string name="keyboard_shortcut_join">or</string>
@@ -3815,7 +3813,7 @@
user what action they need to take in the customization dialog to assign a new custom shortcut.
The shortcut customize dialog allows users to add/remove custom shortcuts
[CHAR LIMIT=NONE] -->
- <string name="shortcut_customize_mode_add_shortcut_description">Press key to assign shortcut</string>
+ <string name="shortcut_customize_mode_add_shortcut_description">To create this shortcut, press the Action key and one or more other keys together</string>
<!-- Sub title at the top of the remove custom shortcut dialog. Explains to the user what action
they're about to take when they click remove shortcut. The shortcut customize dialog allows
users to add/remove custom shortcuts
@@ -3912,7 +3910,7 @@
<!-- Error message displayed when the user select a key combination that is already in use while
assigning a new custom key combination to a shortcut in shortcut helper. The helper is a
component that shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] -->
- <string name="shortcut_customizer_key_combination_in_use_error_message">Key combination already in use. Try another key.</string>
+ <string name="shortcut_customizer_key_combination_in_use_error_message">Key combination already in use. Try another combination.</string>
<!-- Generic error message displayed when the user selected key combination cannot be used as
custom keyboard shortcut in shortcut helper. The helper is a component that shows the user
which keyboard shortcuts they can use and allows users to customize their keyboard
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginEnabler.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginEnabler.java
index 1c5da827eeb3..3d2ce4229bd5 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginEnabler.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginEnabler.java
@@ -27,9 +27,10 @@ public interface PluginEnabler {
int DISABLED_INVALID_VERSION = 2;
int DISABLED_FROM_EXPLICIT_CRASH = 3;
int DISABLED_FROM_SYSTEM_CRASH = 4;
+ int DISABLED_UNKNOWN = 100;
@IntDef({ENABLED, DISABLED_MANUALLY, DISABLED_INVALID_VERSION, DISABLED_FROM_EXPLICIT_CRASH,
- DISABLED_FROM_SYSTEM_CRASH})
+ DISABLED_FROM_SYSTEM_CRASH, DISABLED_UNKNOWN})
@interface DisableReason {
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index 83ca496dbef2..2b71c87bfa27 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -19,10 +19,11 @@ package com.android.systemui.shared.recents;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Bundle;
+import android.os.IRemoteCallback;
import android.view.MotionEvent;
import com.android.systemui.shared.recents.ISystemUiProxy;
-// Next ID: 34
+// Next ID: 36
oneway interface IOverviewProxy {
void onActiveNavBarRegionChanges(in Region activeRegion) = 11;
@@ -137,4 +138,10 @@ oneway interface IOverviewProxy {
* Sent when {@link TaskbarDelegate#appTransitionPending} is called.
*/
void appTransitionPending(boolean pending) = 34;
+
+ /**
+ * Sent right after OverviewProxy calls unbindService() on the TouchInteractionService.
+ * TouchInteractionService is expected to send the reply once it has finished cleaning up.
+ */
+ void onUnbind(IRemoteCallback reply) = 35;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index ff788484c819..ec97b8a96c1f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -208,7 +208,6 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
private final InputMethodManager mInputMethodManager;
private final DelayableExecutor mMainExecutor;
private final Resources mResources;
- private final LiftToActivateListener mLiftToActivateListener;
private final TelephonyManager mTelephonyManager;
private final EmergencyButtonController.Factory mEmergencyButtonControllerFactory;
private final FalsingCollector mFalsingCollector;
@@ -227,7 +226,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
LatencyTracker latencyTracker,
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
InputMethodManager inputMethodManager, @Main DelayableExecutor mainExecutor,
- @Main Resources resources, LiftToActivateListener liftToActivateListener,
+ @Main Resources resources,
TelephonyManager telephonyManager, FalsingCollector falsingCollector,
EmergencyButtonController.Factory emergencyButtonControllerFactory,
DevicePostureController devicePostureController,
@@ -244,7 +243,6 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
mInputMethodManager = inputMethodManager;
mMainExecutor = mainExecutor;
mResources = resources;
- mLiftToActivateListener = liftToActivateListener;
mTelephonyManager = telephonyManager;
mEmergencyButtonControllerFactory = emergencyButtonControllerFactory;
mFalsingCollector = falsingCollector;
@@ -284,7 +282,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
return new KeyguardPinViewController((KeyguardPINView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
- mLiftToActivateListener, emergencyButtonController, mFalsingCollector,
+ emergencyButtonController, mFalsingCollector,
mDevicePostureController, mFeatureFlags, mSelectedUserInteractor,
mUiEventLogger, mKeyguardKeyboardInteractor, mBouncerHapticPlayer,
mUserActivityNotifier);
@@ -292,14 +290,14 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
- mLiftToActivateListener, mTelephonyManager, mFalsingCollector,
+ mTelephonyManager, mFalsingCollector,
emergencyButtonController, mFeatureFlags, mSelectedUserInteractor,
mKeyguardKeyboardInteractor, mBouncerHapticPlayer, mUserActivityNotifier);
} else if (keyguardInputView instanceof KeyguardSimPukView) {
return new KeyguardSimPukViewController((KeyguardSimPukView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
- mLiftToActivateListener, mTelephonyManager, mFalsingCollector,
+ mTelephonyManager, mFalsingCollector,
emergencyButtonController, mFeatureFlags, mSelectedUserInteractor,
mKeyguardKeyboardInteractor, mBouncerHapticPlayer, mUserActivityNotifier
);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index e22736b69213..622b67f25da3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -297,13 +297,10 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
DisappearAnimationUtils disappearAnimationUtils = needsSlowUnlockTransition
? mDisappearAnimationUtilsLocked
: mDisappearAnimationUtils;
- android.util.Log.i("KeyguardPINView", "startDisappearAnimation: " + finishRunnable);
disappearAnimationUtils.createAnimation(
this, 0, 200, mDisappearYTranslation, false,
mDisappearAnimationUtils.getInterpolator(), () -> {
if (finishRunnable != null) {
- android.util.Log.i("KeyguardPINView",
- "startDisappearAnimation, invoking run()");
finishRunnable.run();
}
},
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
index d999994a3312..7f176de547bc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
@@ -34,7 +34,6 @@ import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor;
-import com.android.systemui.Flags;
import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
@@ -44,7 +43,6 @@ import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinBasedInputView>
extends KeyguardAbsKeyInputViewController<T> {
- private final LiftToActivateListener mLiftToActivateListener;
private final FalsingCollector mFalsingCollector;
private final KeyguardKeyboardInteractor mKeyguardKeyboardInteractor;
protected PasswordTextView mPasswordEntry;
@@ -73,7 +71,6 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB
KeyguardSecurityCallback keyguardSecurityCallback,
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
LatencyTracker latencyTracker,
- LiftToActivateListener liftToActivateListener,
EmergencyButtonController emergencyButtonController,
FalsingCollector falsingCollector,
FeatureFlags featureFlags,
@@ -85,7 +82,6 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB
messageAreaControllerFactory, latencyTracker, falsingCollector,
emergencyButtonController, featureFlags, selectedUserInteractor,
bouncerHapticPlayer, userActivityNotifier);
- mLiftToActivateListener = liftToActivateListener;
mFalsingCollector = falsingCollector;
mKeyguardKeyboardInteractor = keyguardKeyboardInteractor;
mPasswordEntry = mView.findViewById(mView.getPasswordTextViewId());
@@ -151,10 +147,6 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB
verifyPasswordAndUnlock();
}
});
-
- if (!Flags.simPinTalkbackFixForDoubleSubmit()) {
- okButton.setOnHoverListener(mLiftToActivateListener);
- }
}
if (pinInputFieldStyledFocusState()) {
collectFlow(mPasswordEntry, mKeyguardKeyboardInteractor.isAnyKeyboardConnected(),
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
index b159a70066ce..9ae4cc6a4b4f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
@@ -56,7 +56,7 @@ public class KeyguardPinViewController
SecurityMode securityMode, LockPatternUtils lockPatternUtils,
KeyguardSecurityCallback keyguardSecurityCallback,
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
- LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener,
+ LatencyTracker latencyTracker,
EmergencyButtonController emergencyButtonController,
FalsingCollector falsingCollector,
DevicePostureController postureController, FeatureFlags featureFlags,
@@ -65,7 +65,7 @@ public class KeyguardPinViewController
BouncerHapticPlayer bouncerHapticPlayer,
UserActivityNotifier userActivityNotifier) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
- messageAreaControllerFactory, latencyTracker, liftToActivateListener,
+ messageAreaControllerFactory, latencyTracker,
emergencyButtonController, falsingCollector, featureFlags, selectedUserInteractor,
keyguardKeyboardInteractor, bouncerHapticPlayer, userActivityNotifier);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
index 52c93f72206b..24f77d77dbe1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -91,7 +91,7 @@ public class KeyguardSimPinViewController
SecurityMode securityMode, LockPatternUtils lockPatternUtils,
KeyguardSecurityCallback keyguardSecurityCallback,
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
- LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener,
+ LatencyTracker latencyTracker,
TelephonyManager telephonyManager, FalsingCollector falsingCollector,
EmergencyButtonController emergencyButtonController, FeatureFlags featureFlags,
SelectedUserInteractor selectedUserInteractor,
@@ -99,7 +99,7 @@ public class KeyguardSimPinViewController
BouncerHapticPlayer bouncerHapticPlayer,
UserActivityNotifier userActivityNotifier) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
- messageAreaControllerFactory, latencyTracker, liftToActivateListener,
+ messageAreaControllerFactory, latencyTracker,
emergencyButtonController, falsingCollector, featureFlags, selectedUserInteractor,
keyguardKeyboardInteractor, bouncerHapticPlayer, userActivityNotifier);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
index 9adc5bae1ada..e17e8cc05f7e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
@@ -89,7 +89,7 @@ public class KeyguardSimPukViewController
SecurityMode securityMode, LockPatternUtils lockPatternUtils,
KeyguardSecurityCallback keyguardSecurityCallback,
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
- LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener,
+ LatencyTracker latencyTracker,
TelephonyManager telephonyManager, FalsingCollector falsingCollector,
EmergencyButtonController emergencyButtonController, FeatureFlags featureFlags,
SelectedUserInteractor selectedUserInteractor,
@@ -97,7 +97,7 @@ public class KeyguardSimPukViewController
BouncerHapticPlayer bouncerHapticPlayer,
UserActivityNotifier userActivityNotifier) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
- messageAreaControllerFactory, latencyTracker, liftToActivateListener,
+ messageAreaControllerFactory, latencyTracker,
emergencyButtonController, falsingCollector, featureFlags, selectedUserInteractor,
keyguardKeyboardInteractor, bouncerHapticPlayer, userActivityNotifier);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
diff --git a/packages/SystemUI/src/com/android/keyguard/LiftToActivateListener.java b/packages/SystemUI/src/com/android/keyguard/LiftToActivateListener.java
deleted file mode 100644
index 425e50ed6397..000000000000
--- a/packages/SystemUI/src/com/android/keyguard/LiftToActivateListener.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.accessibility.AccessibilityManager;
-
-import javax.inject.Inject;
-
-/**
- * Hover listener that implements lift-to-activate interaction for
- * accessibility. May be added to multiple views.
- */
-class LiftToActivateListener implements View.OnHoverListener {
- /** Manager used to query accessibility enabled state. */
- private final AccessibilityManager mAccessibilityManager;
-
- private boolean mCachedClickableState;
-
- @Inject
- LiftToActivateListener(AccessibilityManager accessibilityManager) {
- mAccessibilityManager = accessibilityManager;
- }
-
- @Override
- public boolean onHover(View v, MotionEvent event) {
- // When touch exploration is turned on, lifting a finger while
- // inside the view bounds should perform a click action.
- if (mAccessibilityManager.isEnabled()
- && mAccessibilityManager.isTouchExplorationEnabled()) {
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_HOVER_ENTER:
- // Lift-to-type temporarily disables double-tap
- // activation by setting the view as not clickable.
- mCachedClickableState = v.isClickable();
- v.setClickable(false);
- break;
- case MotionEvent.ACTION_HOVER_EXIT:
- final int x = (int) event.getX();
- final int y = (int) event.getY();
- if ((x > v.getPaddingLeft()) && (y > v.getPaddingTop())
- && (x < v.getWidth() - v.getPaddingRight())
- && (y < v.getHeight() - v.getPaddingBottom())) {
- v.performClick();
- }
- v.setClickable(mCachedClickableState);
- break;
- }
- }
-
- // Pass the event to View.onHoverEvent() to handle accessibility.
- v.onHoverEvent(event);
-
- // Consume the event so it doesn't fall through to other views.
- return true;
- }
-} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/KairosActivatable.kt b/packages/SystemUI/src/com/android/systemui/KairosActivatable.kt
new file mode 100644
index 000000000000..5e29ba91ce42
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/KairosActivatable.kt
@@ -0,0 +1,212 @@
+/*
+ * 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
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.kairos.BuildScope
+import com.android.systemui.kairos.Events
+import com.android.systemui.kairos.EventsLoop
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.Incremental
+import com.android.systemui.kairos.IncrementalLoop
+import com.android.systemui.kairos.KairosNetwork
+import com.android.systemui.kairos.State
+import com.android.systemui.kairos.StateLoop
+import com.android.systemui.kairos.launchKairosNetwork
+import com.android.systemui.kairos.launchScope
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+import dagger.multibindings.Multibinds
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * A Kairos-powered class that needs late-initialization within a Kairos [BuildScope].
+ *
+ * If your class is a [SysUISingleton], you can leverage Dagger to automatically initialize your
+ * instance after SystemUI has initialized:
+ * ```kotlin
+ * class MyClass : KairosActivatable { ... }
+ *
+ * @dagger.Module
+ * interface MyModule {
+ * @Binds
+ * @IntoSet
+ * fun bindKairosActivatable(impl: MyClass): KairosActivatable
+ * }
+ * ```
+ *
+ * Alternatively, you can utilize Dagger's [dagger.assisted.AssistedInject]:
+ * ```kotlin
+ * class MyClass @AssistedInject constructor(...) : KairosActivatable {
+ * @AssistedFactory
+ * interface Factory {
+ * fun create(...): MyClass
+ * }
+ * }
+ *
+ * // When you need an instance:
+ *
+ * class OtherClass @Inject constructor(
+ * private val myClassFactory: MyClass.Factory,
+ * ) {
+ * fun BuildScope.foo() {
+ * val myClass = activated { myClassFactory.create() }
+ * ...
+ * }
+ * }
+ * ```
+ *
+ * @see activated
+ */
+@ExperimentalKairosApi
+fun interface KairosActivatable {
+ /** Initializes any Kairos fields that require a [BuildScope] in order to be constructed. */
+ fun BuildScope.activate()
+}
+
+/** Constructs [KairosActivatable] instances. */
+@ExperimentalKairosApi
+fun interface KairosActivatableFactory<T : KairosActivatable> {
+ fun BuildScope.create(): T
+}
+
+/** Instantiates, [activates][KairosActivatable.activate], and returns a [KairosActivatable]. */
+@ExperimentalKairosApi
+fun <T : KairosActivatable> BuildScope.activated(factory: KairosActivatableFactory<T>): T =
+ factory.run { create() }.apply { activate() }
+
+/**
+ * Utilities for defining [State] and [Events] from a constructor without a provided [BuildScope].
+ * These instances are not active until the builder is [activated][activate]; while you can
+ * immediately use them with other Kairos APIs, the Kairos transaction will be suspended until
+ * initialization is complete.
+ *
+ * ```kotlin
+ * class MyRepository(private val dataSource: DataSource) : KairosBuilder by kairosBuilder() {
+ * val dataSourceEvent = buildEvents<SomeData> {
+ * // inside this lambda, we have access to a BuildScope, which can be used to create
+ * // new inputs to the Kairos network
+ * dataSource.someDataFlow.toEvents()
+ * }
+ * }
+ * ```
+ */
+@ExperimentalKairosApi
+interface KairosBuilder : KairosActivatable {
+ /**
+ * Returns a forward-reference to a [State] that will be instantiated when this builder is
+ * [activated][activate].
+ */
+ fun <R> buildState(block: BuildScope.() -> State<R>): State<R>
+
+ /**
+ * Returns a forward-reference to an [Events] that will be instantiated when this builder is
+ * [activated][activate].
+ */
+ fun <R> buildEvents(block: BuildScope.() -> Events<R>): Events<R>
+
+ fun <K, V> buildIncremental(block: BuildScope.() -> Incremental<K, V>): Incremental<K, V>
+
+ /** Defers [block] until this builder is [activated][activate]. */
+ fun onActivated(block: BuildScope.() -> Unit)
+}
+
+/** Returns an [KairosBuilder] that can only be [activated][KairosActivatable.activate] once. */
+@ExperimentalKairosApi fun kairosBuilder(): KairosBuilder = KairosBuilderImpl()
+
+@OptIn(ExperimentalKairosApi::class)
+private class KairosBuilderImpl @Inject constructor() : KairosBuilder {
+
+ // TODO: atomic?
+ // TODO: are two lists really necessary?
+ private var _builds: MutableList<KairosActivatable>? = mutableListOf()
+ private var _startables: MutableList<KairosActivatable>? = mutableListOf()
+
+ private val startables
+ get() = checkNotNull(_startables) { "Kairos network has already been initialized" }
+
+ private val builds
+ get() = checkNotNull(_builds) { "Kairos network has already been initialized" }
+
+ override fun <R> buildState(block: BuildScope.() -> State<R>): State<R> =
+ StateLoop<R>().apply { builds.add { loopback = block() } }
+
+ override fun <R> buildEvents(block: BuildScope.() -> Events<R>): Events<R> =
+ EventsLoop<R>().apply { builds.add { loopback = block() } }
+
+ override fun <K, V> buildIncremental(
+ block: BuildScope.() -> Incremental<K, V>
+ ): Incremental<K, V> = IncrementalLoop<K, V>().apply { builds.add { loopback = block() } }
+
+ override fun onActivated(block: BuildScope.() -> Unit) {
+ startables.add { block() }
+ }
+
+ override fun BuildScope.activate() {
+ builds.forEach { it.run { activate() } }
+ _builds = null
+ deferredBuildScopeAction {
+ startables.forEach { it.run { activate() } }
+ _startables = null
+ }
+ }
+}
+
+/** Initializes [KairosActivatables][KairosActivatable] after SystemUI is initialized. */
+@SysUISingleton
+@ExperimentalKairosApi
+class KairosCoreStartable
+@Inject
+constructor(
+ @Application private val appScope: CoroutineScope,
+ private val kairosNetwork: KairosNetwork,
+ private val activatables: dagger.Lazy<Set<@JvmSuppressWildcards KairosActivatable>>,
+) : CoreStartable {
+ override fun start() {
+ appScope.launch {
+ kairosNetwork.activateSpec {
+ for (activatable in activatables.get()) {
+ launchScope { activatable.run { activate() } }
+ }
+ }
+ }
+ }
+}
+
+@Module
+@ExperimentalKairosApi
+interface KairosCoreStartableModule {
+ @Binds
+ @IntoMap
+ @ClassKey(KairosCoreStartable::class)
+ fun bindCoreStartable(impl: KairosCoreStartable): CoreStartable
+
+ @Multibinds fun kairosActivatables(): Set<@JvmSuppressWildcards KairosActivatable>
+
+ companion object {
+ @Provides
+ @SysUISingleton
+ fun provideKairosNetwork(@Application scope: CoroutineScope): KairosNetwork =
+ scope.launchKairosNetwork()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationImpl.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationImpl.java
index 5b433464c1c6..5cba464fc24c 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationImpl.java
@@ -609,15 +609,12 @@ public class MagnificationImpl implements Magnification, CommandQueue.Callbacks
final WindowMagnificationController windowMagnificationController =
mWindowMagnificationControllerSupplier.get(displayId);
if (windowMagnificationController != null) {
- boolean isWindowMagnifierActivated = windowMagnificationController.isActivated();
- if (isWindowMagnifierActivated) {
- windowMagnificationController.updateDragHandleResourcesIfNeeded(shown);
- }
+ windowMagnificationController.updateDragHandleResourcesIfNeeded(shown);
if (shown) {
mA11yLogger.logWithPosition(
MagnificationSettingsEvent.MAGNIFICATION_SETTINGS_PANEL_OPENED,
- isWindowMagnifierActivated
+ windowMagnificationController.isActivated()
? ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
: ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN
);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 08d3e17c03d7..1587ab16fc38 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -1519,12 +1519,12 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
}
void updateDragHandleResourcesIfNeeded(boolean settingsPanelIsShown) {
+ mSettingsPanelVisibility = settingsPanelIsShown;
+
if (!isActivated()) {
return;
}
- mSettingsPanelVisibility = settingsPanelIsShown;
-
mDragView.setBackground(mContext.getResources().getDrawable(settingsPanelIsShown
? R.drawable.accessibility_window_magnification_drag_handle_background_change_inset
: R.drawable.accessibility_window_magnification_drag_handle_background_inset));
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
index 030d147e21c3..edbede8fa865 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
@@ -24,6 +24,7 @@ import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
+import android.view.DisplayCutout;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.OvershootInterpolator;
@@ -197,7 +198,7 @@ class MenuAnimationController {
constrainPositionAndUpdate(position, /* writeToPosition = */ true);
}
- void flingMenuThenSpringToEdge(float x, float velocityX, float velocityY) {
+ void flingMenuThenSpringToEdge(PointF position, float velocityX, float velocityY) {
final boolean shouldMenuFlingLeft = isOnLeftSide()
? velocityX < ESCAPE_VELOCITY
: velocityX < -ESCAPE_VELOCITY;
@@ -205,9 +206,17 @@ class MenuAnimationController {
final Rect draggableBounds = mMenuView.getMenuDraggableBounds();
final float finalPositionX = shouldMenuFlingLeft
? draggableBounds.left : draggableBounds.right;
-
+ final DisplayCutout displayCutout = mMenuViewAppearance.getDisplayCutout();
+ final float finalPositionY =
+ (displayCutout == null) ? position.y
+ : mMenuViewAppearance.avoidVerticalDisplayCutout(
+ position.y, draggableBounds,
+ shouldMenuFlingLeft
+ ? displayCutout.getBoundingRectLeft()
+ : displayCutout.getBoundingRectRight()
+ );
final float minimumVelocityToReachEdge =
- (finalPositionX - x) * (FLING_FRICTION_SCALAR * DEFAULT_FRICTION);
+ (finalPositionX - position.x) * (FLING_FRICTION_SCALAR * DEFAULT_FRICTION);
final float startXVelocity = shouldMenuFlingLeft
? Math.min(minimumVelocityToReachEdge, velocityX)
@@ -219,11 +228,19 @@ class MenuAnimationController {
createSpringForce(),
finalPositionX);
- flingThenSpringMenuWith(DynamicAnimation.TRANSLATION_Y,
- velocityY,
- FLING_FRICTION_SCALAR,
- createSpringForce(),
- /* finalPosition= */ null);
+ if (com.android.systemui.Flags.floatingMenuDisplayCutoutSupport()) {
+ flingThenSpringMenuWith(DynamicAnimation.TRANSLATION_Y,
+ velocityY,
+ FLING_FRICTION_SCALAR,
+ createSpringForce(),
+ (finalPositionY != position.y) ? finalPositionY : null);
+ } else {
+ flingThenSpringMenuWith(DynamicAnimation.TRANSLATION_Y,
+ velocityY,
+ FLING_FRICTION_SCALAR,
+ createSpringForce(),
+ /* finalPosition= */ null);
+ }
}
private void flingThenSpringMenuWith(DynamicAnimation.ViewProperty property, float velocity,
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java
index a1cb0367421b..bb6ab51aa56a 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java
@@ -266,7 +266,7 @@ class MenuInfoRepository {
mSecureSettings.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS),
/* notifyForDescendants */ false, mMenuTargetFeaturesContentObserver,
UserHandle.USER_CURRENT);
- if (!com.android.systemui.Flags.floatingMenuNarrowTargetContentObserver()) {
+ if (com.android.systemui.Flags.floatingMenuNotifyTargetsChangedOnStrictDiff()) {
mSecureSettings.registerContentObserverForUserSync(
mSecureSettings.getUriFor(ENABLED_ACCESSIBILITY_SERVICES),
/* notifyForDescendants */ false,
@@ -287,7 +287,7 @@ class MenuInfoRepository {
UserHandle.USER_CURRENT);
mContext.registerComponentCallbacks(mComponentCallbacks);
- if (!com.android.systemui.Flags.floatingMenuNarrowTargetContentObserver()) {
+ if (com.android.systemui.Flags.floatingMenuNotifyTargetsChangedOnStrictDiff()) {
mAccessibilityManager.addAccessibilityServicesStateChangeListener(
mA11yServicesStateChangeListener);
}
@@ -317,7 +317,7 @@ class MenuInfoRepository {
mContext.getContentResolver().unregisterContentObserver(mMenuFadeOutContentObserver);
mContext.unregisterComponentCallbacks(mComponentCallbacks);
- if (!com.android.systemui.Flags.floatingMenuNarrowTargetContentObserver()) {
+ if (com.android.systemui.Flags.floatingMenuNotifyTargetsChangedOnStrictDiff()) {
mAccessibilityManager.removeAccessibilityServicesStateChangeListener(
mA11yServicesStateChangeListener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java
index 9511e3769a8d..aca020d235be 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java
@@ -105,7 +105,8 @@ class MenuListViewTouchHandler implements RecyclerView.OnItemTouchListener {
if (mDragToInteractAnimationController.maybeConsumeUpMotionEvent(motionEvent)
== empty) {
mVelocityTracker.computeCurrentVelocity(VELOCITY_UNIT_SECONDS);
- mMenuAnimationController.flingMenuThenSpringToEdge(endX,
+ mMenuAnimationController.flingMenuThenSpringToEdge(
+ new PointF(endX, mMenuTranslationDown.y + dy),
mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
mMenuAnimationController.fadeOutIfEnabled();
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
index 3f49010aaaab..ae39b72b2585 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
@@ -284,13 +284,36 @@ class MenuView extends FrameLayout implements
onEdgeChanged();
onPositionChanged();
- if (mFeaturesChangeListener != null) {
+ boolean shouldSendFeatureChangeNotification =
+ com.android.systemui.Flags.floatingMenuNotifyTargetsChangedOnStrictDiff()
+ ? !areFeatureListsIdentical(targetFeatures, newTargetFeatures)
+ : true;
+ if (mFeaturesChangeListener != null && shouldSendFeatureChangeNotification) {
mFeaturesChangeListener.onChange(newTargetFeatures);
}
mMenuAnimationController.fadeOutIfEnabled();
}
+ /**
+ * Returns true if the given feature lists are identical lists, i.e. the same list of {@link
+ * AccessibilityTarget} (equality checked via UID) in the same order.
+ */
+ private boolean areFeatureListsIdentical(
+ List<AccessibilityTarget> currentFeatures, List<AccessibilityTarget> newFeatures) {
+ if (currentFeatures.size() != newFeatures.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < currentFeatures.size(); i++) {
+ if (currentFeatures.get(i).getUid() != newFeatures.get(i).getUid()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
private void onMenuFadeEffectInfoChanged(MenuFadeEffectInfo fadeEffectInfo) {
mMenuAnimationController.updateOpacityWith(fadeEffectInfo.isFadeEffectEnabled(),
fadeEffectInfo.getOpacity());
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java
index a700cbef2e16..bd3dfe049587 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java
@@ -28,12 +28,14 @@ import android.graphics.Insets;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.view.DisplayCutout;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowMetrics;
import androidx.annotation.DimenRes;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.res.R;
import java.lang.annotation.Retention;
@@ -291,7 +293,7 @@ class MenuViewAppearance {
final WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics();
final WindowInsets windowInsets = windowMetrics.getWindowInsets();
final Insets insets = windowInsets.getInsetsIgnoringVisibility(
- WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout());
+ WindowInsets.Type.systemBars());
final Rect bounds = new Rect(windowMetrics.getBounds());
bounds.left += insets.left;
@@ -302,6 +304,37 @@ class MenuViewAppearance {
return bounds;
}
+ DisplayCutout getDisplayCutout() {
+ return mWindowManager.getCurrentWindowMetrics().getWindowInsets().getDisplayCutout();
+ }
+
+ float avoidVerticalDisplayCutout(float y, Rect bounds, Rect cutout) {
+ int menuHeight = calculateActualMenuHeight();
+ return avoidVerticalDisplayCutout(y, menuHeight, bounds, cutout);
+ }
+
+ @VisibleForTesting
+ public static float avoidVerticalDisplayCutout(
+ float y, float menuHeight, Rect bounds, Rect cutout) {
+ if (cutout.top > y + menuHeight || cutout.bottom < y) {
+ return y;
+ }
+
+ boolean topAvailable = cutout.top - bounds.top >= menuHeight;
+ boolean bottomAvailable = bounds.bottom - cutout.bottom >= menuHeight;
+ boolean topOrBottom;
+ if (!topAvailable && !bottomAvailable) {
+ return y;
+ } else if (topAvailable && !bottomAvailable) {
+ topOrBottom = true;
+ } else if (!topAvailable && bottomAvailable) {
+ topOrBottom = false;
+ } else {
+ topOrBottom = y + menuHeight * 0.5f < cutout.centerY();
+ }
+ return (topOrBottom) ? cutout.top - menuHeight : cutout.bottom;
+ }
+
boolean isMenuOnLeftSide() {
return mPercentagePosition.getPercentageX() < 0.5f;
}
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 7a674e2fa6f1..81095220b4a6 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
@@ -21,17 +21,12 @@ import static android.view.WindowInsets.Type.ime;
import static androidx.core.view.WindowInsetsCompat.Type;
import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_BUTTON_COMPONENT_NAME;
-import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType.INVISIBLE_TOGGLE;
-import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
-import static com.android.internal.accessibility.util.AccessibilityUtils.getAccessibilityServiceFragmentType;
-import static com.android.internal.accessibility.util.AccessibilityUtils.setAccessibilityServiceState;
import static com.android.systemui.accessibility.floatingmenu.MenuMessageView.Index;
import static com.android.systemui.accessibility.floatingmenu.MenuNotificationFactory.ACTION_DELETE;
import static com.android.systemui.accessibility.floatingmenu.MenuNotificationFactory.ACTION_UNDO;
import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat;
-import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.IntDef;
import android.annotation.StringDef;
import android.annotation.SuppressLint;
@@ -39,7 +34,6 @@ import android.app.NotificationManager;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -174,46 +168,13 @@ class MenuViewLayer extends FrameLayout implements
final Runnable mDismissMenuAction = new Runnable() {
@Override
public void run() {
- if (android.view.accessibility.Flags.a11yQsShortcut()) {
- mAccessibilityManager.enableShortcutsForTargets(
- /* enable= */ false,
- ShortcutConstants.UserShortcutType.SOFTWARE,
- new ArraySet<>(
- mAccessibilityManager.getAccessibilityShortcutTargets(SOFTWARE)),
- mSecureSettings.getRealUserHandle(UserHandle.USER_CURRENT)
- );
- } else {
- mSecureSettings.putStringForUser(
- Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, /* value= */ "",
- UserHandle.USER_CURRENT);
-
- final List<ComponentName> hardwareKeyShortcutComponents =
- mAccessibilityManager.getAccessibilityShortcutTargets(HARDWARE)
- .stream()
- .map(ComponentName::unflattenFromString)
- .toList();
-
- // Should disable the corresponding service when the fragment type is
- // INVISIBLE_TOGGLE, which will enable service when the shortcut is on.
- final List<AccessibilityServiceInfo> serviceInfoList =
- mAccessibilityManager.getEnabledAccessibilityServiceList(
- AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
- serviceInfoList.forEach(info -> {
- if (getAccessibilityServiceFragmentType(info) != INVISIBLE_TOGGLE) {
- return;
- }
-
- final ComponentName serviceComponentName = info.getComponentName();
- if (hardwareKeyShortcutComponents.contains(serviceComponentName)) {
- return;
- }
-
- setAccessibilityServiceState(
- getContext(), serviceComponentName, /* enabled= */ false,
- mSecureSettings.getRealUserHandle(UserHandle.USER_CURRENT));
- });
- }
-
+ mAccessibilityManager.enableShortcutsForTargets(
+ /* enable= */ false,
+ ShortcutConstants.UserShortcutType.SOFTWARE,
+ new ArraySet<>(
+ mAccessibilityManager.getAccessibilityShortcutTargets(SOFTWARE)),
+ mSecureSettings.getRealUserHandle(UserHandle.USER_CURRENT)
+ );
mFloatingMenu.hide();
}
};
@@ -516,7 +477,7 @@ class MenuViewLayer extends FrameLayout implements
return;
}
mMenuAnimationController.flingMenuThenSpringToEdge(
- mMenuView.getMenuPosition().x, 100f, 0f);
+ mMenuView.getMenuPosition(), 100f, 0f);
Intent intent = getIntentForEditScreen();
PackageManager packageManager = getContext().getPackageManager();
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 73aabc3cf95a..438184d4d2d6 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
@@ -286,9 +286,7 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate,
if (com.android.settingslib.flags.Flags.hearingDevicesAmbientVolumeControl()) {
setupAmbientControls();
}
- if (com.android.systemui.Flags.hearingDevicesDialogRelatedTools()) {
- setupRelatedToolsView(dialog);
- }
+ setupRelatedToolsView(dialog);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogReceiver.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogReceiver.java
index 02e65fd9031b..90b8fa0177b7 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogReceiver.java
@@ -22,8 +22,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import com.android.systemui.Flags;
-
import javax.inject.Inject;
/**
@@ -43,10 +41,6 @@ public class HearingDevicesDialogReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- if (!Flags.hearingAidsQsTileDialog()) {
- return;
- }
-
if (ACTION.equals(intent.getAction())) {
mDialogManager.showDialog(/* expandable= */ null, LAUNCH_SOURCE_A11Y);
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt b/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt
index 610e3f8a8c84..fb47d429e271 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt
@@ -411,7 +411,7 @@ interface QSAccessibilityModule {
stateInteractor: HearingDevicesTileDataInteractor,
userActionInteractor: HearingDevicesTileUserActionInteractor,
): QSTileViewModel {
- return if (Flags.hearingAidsQsTileDialog() && Flags.qsNewTilesFuture()) {
+ return if (Flags.qsNewTilesFuture()) {
factory.create(
TileSpec.create(HEARING_DEVICES_TILE_SPEC),
userActionInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
index 68ec0f2d57ef..39f55803bb73 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
@@ -68,7 +68,7 @@ interface FingerprintPropertyRepository {
val sensorType: StateFlow<FingerprintSensorType>
/** The sensor location relative to each physical display. */
- val sensorLocations: Flow<Map<String, SensorLocationInternal>>
+ val sensorLocations: StateFlow<Map<String, SensorLocationInternal>>
}
@SysUISingleton
@@ -128,12 +128,14 @@ constructor(
initialValue = props.value.sensorType.toSensorType(),
)
- override val sensorLocations: Flow<Map<String, SensorLocationInternal>> =
- props.map {
- it.allLocations.associateBy { sensorLocationInternal ->
- sensorLocationInternal.displayId
- }
- }
+ override val sensorLocations: StateFlow<Map<String, SensorLocationInternal>> =
+ props
+ .map { props -> props.allLocations.associateBy { it.displayId } }
+ .stateIn(
+ applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = props.value.allLocations.associateBy { it.displayId },
+ )
override val propertiesInitialized: Flow<Boolean> =
combine(
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
index d9ed9ca1f07b..ae855d19715e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
@@ -20,11 +20,11 @@ import android.content.Context
import android.graphics.Rect
import android.hardware.biometrics.SensorLocationInternal
import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
-import com.android.systemui.biometrics.shared.model.SensorLocation
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.shared.customization.data.SensorLocation
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
@@ -42,8 +42,8 @@ class FingerprintPropertyInteractor
constructor(
@Application private val applicationScope: CoroutineScope,
@Application private val context: Context,
- repository: FingerprintPropertyRepository,
- @Main configurationInteractor: ConfigurationInteractor,
+ private val repository: FingerprintPropertyRepository,
+ @Main private val configurationInteractor: ConfigurationInteractor,
displayStateInteractor: DisplayStateInteractor,
udfpsOverlayInteractor: UdfpsOverlayInteractor,
) {
@@ -61,11 +61,16 @@ constructor(
* Devices with multiple physical displays use unique display ids to determine which sensor is
* on the active physical display. This value represents a unique physical display id.
*/
- private val uniqueDisplayId: Flow<String> =
+ private val uniqueDisplayId: StateFlow<String> =
displayStateInteractor.displayChanges
- .map { context.display?.uniqueId }
+ .map { context.display.uniqueId }
.filterNotNull()
.distinctUntilChanged()
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = EMPTY_DISPLAY_ID,
+ )
/**
* Sensor location for the:
@@ -73,13 +78,15 @@ constructor(
* - device's natural screen resolution
* - device's natural orientation
*/
- private val unscaledSensorLocation: Flow<SensorLocationInternal> =
- combine(repository.sensorLocations, uniqueDisplayId) { locations, displayId ->
+ private val unscaledSensorLocation: StateFlow<SensorLocationInternal> =
+ combineStates(repository.sensorLocations, uniqueDisplayId, applicationScope) {
+ locations,
+ displayId ->
// Devices without multiple physical displays do not use the display id as the key;
// instead, the key is an empty string.
locations.getOrDefault(
displayId,
- locations.getOrDefault("", SensorLocationInternal.DEFAULT),
+ locations.getOrDefault(EMPTY_DISPLAY_ID, SensorLocationInternal.DEFAULT),
)
}
@@ -89,18 +96,18 @@ constructor(
* - current screen resolution
* - device's natural orientation
*/
- val sensorLocation: Flow<SensorLocation> =
- combine(unscaledSensorLocation, configurationInteractor.scaleForResolution) {
+ val sensorLocation: StateFlow<SensorLocation> =
+ combineStates(
unscaledSensorLocation,
- scale ->
- val sensorLocation =
- SensorLocation(
- naturalCenterX = unscaledSensorLocation.sensorLocationX,
- naturalCenterY = unscaledSensorLocation.sensorLocationY,
- naturalRadius = unscaledSensorLocation.sensorRadius,
- scale = scale,
- )
- sensorLocation
+ configurationInteractor.scaleForResolution,
+ applicationScope,
+ ) { unscaledSensorLocation, scale ->
+ SensorLocation(
+ naturalCenterX = unscaledSensorLocation.sensorLocationX,
+ naturalCenterY = unscaledSensorLocation.sensorLocationY,
+ naturalRadius = unscaledSensorLocation.sensorRadius,
+ scale = scale,
+ )
}
/**
@@ -111,4 +118,19 @@ constructor(
*/
val udfpsSensorBounds: Flow<Rect> =
udfpsOverlayInteractor.udfpsOverlayParams.map { it.sensorBounds }.distinctUntilChanged()
+
+ companion object {
+
+ private const val EMPTY_DISPLAY_ID = ""
+
+ /** Combine two state flows to another state flow. */
+ private fun <T1, T2, R> combineStates(
+ flow1: StateFlow<T1>,
+ flow2: StateFlow<T2>,
+ scope: CoroutineScope,
+ transform: (T1, T2) -> R,
+ ): StateFlow<R> =
+ combine(flow1, flow2) { v1, v2 -> transform(v1, v2) }
+ .stateIn(scope, SharingStarted.Eagerly, transform(flow1.value, flow2.value))
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
index 22b2888a51a9..a44778657d25 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
@@ -16,6 +16,7 @@
package com.android.systemui.bouncer.data.repository
+import android.annotation.SuppressLint
import android.os.Build
import android.util.Log
import com.android.keyguard.KeyguardSecurityModel
@@ -51,7 +52,11 @@ interface KeyguardBouncerRepository {
val primaryBouncerShow: StateFlow<Boolean>
val primaryBouncerShowingSoon: StateFlow<Boolean>
val primaryBouncerStartingToHide: StateFlow<Boolean>
- val primaryBouncerStartingDisappearAnimation: StateFlow<Runnable?>
+ val primaryBouncerStartingDisappearAnimation: MutableSharedFlow<Runnable?>
+
+ fun isPrimaryBouncerStartingDisappearAnimation(): Boolean
+
+ fun isDebuggable(): Boolean
/** Determines if we want to instantaneously show the primary bouncer instead of translating. */
val primaryBouncerScrimmed: StateFlow<Boolean>
@@ -128,7 +133,7 @@ interface KeyguardBouncerRepository {
}
@SysUISingleton
-class KeyguardBouncerRepositoryImpl
+open class KeyguardBouncerRepositoryImpl
@Inject
constructor(
private val clock: SystemClock,
@@ -144,9 +149,19 @@ constructor(
override val primaryBouncerShowingSoon = _primaryBouncerShowingSoon.asStateFlow()
private val _primaryBouncerStartingToHide = MutableStateFlow(false)
override val primaryBouncerStartingToHide = _primaryBouncerStartingToHide.asStateFlow()
- private val _primaryBouncerDisappearAnimation = MutableStateFlow<Runnable?>(null)
+
+ @SuppressLint("SharedFlowCreation")
override val primaryBouncerStartingDisappearAnimation =
- _primaryBouncerDisappearAnimation.asStateFlow()
+ MutableSharedFlow<Runnable?>(extraBufferCapacity = 2, replay = 1)
+
+ override fun isPrimaryBouncerStartingDisappearAnimation(): Boolean {
+ val replayCache = primaryBouncerStartingDisappearAnimation.replayCache
+ return if (!replayCache.isEmpty()) {
+ replayCache.last() != null
+ } else {
+ false
+ }
+ }
/** Determines if we want to instantaneously show the primary bouncer instead of translating. */
private val _primaryBouncerScrimmed = MutableStateFlow(false)
@@ -177,6 +192,7 @@ constructor(
_keyguardAuthenticatedPrimaryAuth.asSharedFlow()
/** Whether the user requested to show the bouncer when device is already authenticated */
+ @SuppressLint("SharedFlowCreation")
private val _userRequestedBouncerWhenAlreadyAuthenticated = MutableSharedFlow<Int>()
override val userRequestedBouncerWhenAlreadyAuthenticated: Flow<Int> =
_userRequestedBouncerWhenAlreadyAuthenticated.asSharedFlow()
@@ -226,7 +242,7 @@ constructor(
}
override fun setPrimaryStartDisappearAnimation(runnable: Runnable?) {
- _primaryBouncerDisappearAnimation.value = runnable
+ primaryBouncerStartingDisappearAnimation.tryEmit(runnable)
}
override fun setPanelExpansion(panelExpansion: Float) {
@@ -265,9 +281,11 @@ constructor(
_lastShownSecurityMode.value = securityMode
}
+ override fun isDebuggable() = Build.IS_DEBUGGABLE
+
/** Sets up logs for state flows. */
private fun setUpLogging() {
- if (!Build.IS_DEBUGGABLE) {
+ if (!isDebuggable()) {
return
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
index 641400a50c89..0c6d7920d7f3 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
@@ -22,6 +22,7 @@ import android.os.Handler
import android.os.Trace
import android.util.Log
import android.view.View
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.DejankUtils
@@ -54,7 +55,6 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map
-import com.android.app.tracing.coroutines.launchTraced as launch
/**
* Encapsulates business logic for interacting with the lock-screen primary (pin/pattern/password)
@@ -145,7 +145,7 @@ constructor(
TAG,
"PrimaryBouncerInteractor#show is being called before the " +
"primaryBouncerDelegate is set. Let's exit early so we don't " +
- "set the wrong primaryBouncer state."
+ "set the wrong primaryBouncer state.",
)
return false
}
@@ -197,7 +197,7 @@ constructor(
if (isFullyShowing()) {
SysUiStatsLog.write(
SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED,
- SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__HIDDEN
+ SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__HIDDEN,
)
dismissCallbackRegistry.notifyDismissCancelled()
}
@@ -223,7 +223,7 @@ constructor(
fun setPanelExpansion(expansion: Float) {
val oldExpansion = repository.panelExpansionAmount.value
val expansionChanged = oldExpansion != expansion
- if (repository.primaryBouncerStartingDisappearAnimation.value == null) {
+ if (!repository.isPrimaryBouncerStartingDisappearAnimation()) {
repository.setPanelExpansion(expansion)
}
@@ -272,7 +272,7 @@ constructor(
*/
fun setDismissAction(
onDismissAction: ActivityStarter.OnDismissAction?,
- cancelAction: Runnable?
+ cancelAction: Runnable?,
) {
repository.bouncerDismissActionModel =
if (onDismissAction != null && cancelAction != null) {
@@ -344,7 +344,7 @@ constructor(
fun isFullyShowing(): Boolean {
return (repository.primaryBouncerShowingSoon.value || isBouncerShowing()) &&
repository.panelExpansionAmount.value == KeyguardBouncerConstants.EXPANSION_VISIBLE &&
- repository.primaryBouncerStartingDisappearAnimation.value == null
+ !repository.isPrimaryBouncerStartingDisappearAnimation()
}
/** Returns whether bouncer is scrimmed. */
@@ -361,7 +361,7 @@ constructor(
/** Return whether bouncer is animating away. */
fun isAnimatingAway(): Boolean {
- return repository.primaryBouncerStartingDisappearAnimation.value != null
+ return repository.isPrimaryBouncerStartingDisappearAnimation()
}
/** Return whether bouncer will dismiss with actions */
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
index d5c815d649c4..434a9ce58c3b 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
@@ -170,8 +170,6 @@ object KeyguardBouncerViewBinder {
launch {
viewModel.startDisappearAnimation.collect {
- android.util.Log.i("KeyguardBouncerViewBinder",
- "viewModel.startDisappearAnimation: $it")
securityContainerController.startDisappearAnimation(it)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/composable/BouncerContainer.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/composable/BouncerContainer.kt
index c05dcd5cea83..c59c6816a350 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/composable/BouncerContainer.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/composable/BouncerContainer.kt
@@ -41,13 +41,12 @@ fun BouncerContainer(
Box {
Canvas(Modifier.fillMaxSize()) { drawRect(color = backgroundColor) }
- // Separate the bouncer content into a reusable composable that
- // doesn't have any SceneScope
- // dependencies
+ // Separate the bouncer content into a reusable composable that doesn't have any
+ // ContentScope dependencies
BouncerContent(
bouncerViewModel,
dialogFactory,
- Modifier.sysuiResTag(Bouncer.TestTags.Root).fillMaxSize()
+ Modifier.sysuiResTag(Bouncer.TestTags.Root).fillMaxSize(),
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
index 5baec1e025e8..73aaf7f8e460 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
@@ -29,11 +29,11 @@ import android.view.KeyEvent.isConfirmKey
import android.view.View
import androidx.compose.ui.input.key.KeyEvent
import androidx.compose.ui.input.key.KeyEventType
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.keyguard.PinShapeAdapter
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.bouncer.domain.interactor.SimBouncerInteractor
-import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlags
import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer
import com.android.systemui.res.R
import dagger.assisted.Assisted
@@ -50,7 +50,6 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.receiveAsFlow
-import com.android.app.tracing.coroutines.launchTraced as launch
/** Holds UI state and handles user input for the PIN code bouncer UI. */
class PinBouncerViewModel
@@ -289,11 +288,10 @@ constructor(
* feedback on the view.
*/
fun onDigitButtonDown(view: View?) {
- if (ComposeBouncerFlags.isOnlyComposeBouncerEnabled()) {
- // Current PIN bouncer informs FalsingInteractor#avoidGesture() upon every Pin button
- // touch.
- super.onDown()
- }
+ // This ends up calling FalsingInteractor#avoidGesture() each time a PIN button is touched.
+ // It helps make sure that legitimate touch in the PIN bouncer isn't treated as false touch.
+ super.onDown()
+
if (bouncerHapticPlayer?.isEnabled == true) {
bouncerHapticPlayer.playNumpadKeyFeedback()
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCoreStartable.kt
index b79538aac3e6..60cdccdeaadd 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCoreStartable.kt
@@ -21,8 +21,9 @@ import javax.inject.Inject
/** Initializes classes related to falsing. */
@SysUISingleton
-class FalsingCoreStartable @Inject constructor(val falsingCollector: FalsingCollector) :
- CoreStartable {
+class FalsingCoreStartable
+@Inject
+constructor(@FalsingCollectorActual val falsingCollector: FalsingCollector) : CoreStartable {
override fun start() {
falsingCollector.init()
}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardImageLoader.kt b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardImageLoader.kt
index 8814a1298e44..c0ad3b8c97c9 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardImageLoader.kt
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardImageLoader.kt
@@ -20,15 +20,17 @@ import android.graphics.Bitmap
import android.net.Uri
import android.util.Log
import android.util.Size
-import com.android.systemui.res.R
+import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.systemui.Flags.clipboardOverlayMultiuser
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.res.R
+import com.android.systemui.settings.UserTracker
import java.io.IOException
import java.util.function.Consumer
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
-import com.android.app.tracing.coroutines.launchTraced as launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull
@@ -36,8 +38,9 @@ class ClipboardImageLoader
@Inject
constructor(
private val context: Context,
+ private val userTracker: UserTracker,
@Background private val bgDispatcher: CoroutineDispatcher,
- @Application private val mainScope: CoroutineScope
+ @Application private val mainScope: CoroutineScope,
) {
private val TAG: String = "ClipboardImageLoader"
@@ -46,7 +49,15 @@ constructor(
withContext(bgDispatcher) {
try {
val size = context.resources.getDimensionPixelSize(R.dimen.overlay_x_scale)
- context.contentResolver.loadThumbnail(uri, Size(size, size * 4), null)
+ if (clipboardOverlayMultiuser()) {
+ userTracker.userContentResolver.loadThumbnail(
+ uri,
+ Size(size, size * 4),
+ null,
+ )
+ } else {
+ context.contentResolver.loadThumbnail(uri, Size(size, size * 4), null)
+ }
} catch (e: IOException) {
Log.e(TAG, "Thumbnail loading failed!", e)
null
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
index 747a2a9bd887..7fcdd9596049 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
@@ -52,7 +52,7 @@ interface ConfigurationRepository {
/** Called whenever the configuration has changed. */
val onConfigurationChange: Flow<Unit>
- val scaleForResolution: Flow<Float>
+ val scaleForResolution: StateFlow<Float>
val configurationValues: Flow<Configuration>
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/domain/interactor/ConfigurationInteractor.kt b/packages/SystemUI/src/com/android/systemui/common/ui/domain/interactor/ConfigurationInteractor.kt
index 97a23e1a5010..4d39b033cd7b 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/domain/interactor/ConfigurationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/domain/interactor/ConfigurationInteractor.kt
@@ -23,6 +23,7 @@ import android.view.Surface
import com.android.systemui.common.ui.data.repository.ConfigurationRepository
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
@@ -60,7 +61,7 @@ interface ConfigurationInteractor {
val configurationValues: Flow<Configuration>
/** Emits the current resolution scaling factor */
- val scaleForResolution: Flow<Float>
+ val scaleForResolution: StateFlow<Float>
/** Given [resourceId], emit the dimension pixel size on config change */
fun dimensionPixelSize(resourceId: Int): Flow<Int>
@@ -121,5 +122,5 @@ class ConfigurationInteractorImpl(private val repository: ConfigurationRepositor
override val configurationValues: Flow<Configuration> = repository.configurationValues
- override val scaleForResolution: Flow<Float> = repository.scaleForResolution
+ override val scaleForResolution: StateFlow<Float> = repository.scaleForResolution
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/DevicePosturingCommandListener.kt b/packages/SystemUI/src/com/android/systemui/communal/DevicePosturingCommandListener.kt
new file mode 100644
index 000000000000..c7b7050340a0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/DevicePosturingCommandListener.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.annotation.SuppressLint
+import android.app.DreamManager
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.commandline.Command
+import com.android.systemui.statusbar.commandline.CommandRegistry
+import java.io.PrintWriter
+import javax.inject.Inject
+
+@SysUISingleton
+class DevicePosturingCommandListener
+@Inject
+constructor(private val commandRegistry: CommandRegistry, private val dreamManager: DreamManager) :
+ CoreStartable {
+ private val command = DevicePosturingCommand()
+
+ override fun start() {
+ commandRegistry.registerCommand(COMMAND_ROOT) { command }
+ }
+
+ internal inner class DevicePosturingCommand : Command {
+ @SuppressLint("MissingPermission")
+ override fun execute(pw: PrintWriter, args: List<String>) {
+ val arg = args.getOrNull(0)
+ if (arg == null || arg.lowercase() == "help") {
+ help(pw)
+ return
+ }
+
+ when (arg.lowercase()) {
+ "true" -> dreamManager.setDevicePostured(true)
+ "false" -> dreamManager.setDevicePostured(false)
+ else -> {
+ pw.println("Invalid argument!")
+ help(pw)
+ }
+ }
+ }
+
+ override fun help(pw: PrintWriter) {
+ pw.println("Usage: $ adb shell cmd statusbar device-postured <true|false>")
+ }
+ }
+
+ private companion object {
+ const val COMMAND_ROOT = "device-postured"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt
index 2d19b026489c..e3443227685f 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt
@@ -22,6 +22,7 @@ import com.android.systemui.communal.CommunalDreamStartable
import com.android.systemui.communal.CommunalMetricsStartable
import com.android.systemui.communal.CommunalOngoingContentStartable
import com.android.systemui.communal.CommunalSceneStartable
+import com.android.systemui.communal.DevicePosturingCommandListener
import com.android.systemui.communal.log.CommunalLoggerStartable
import com.android.systemui.communal.widgets.CommunalAppWidgetHostStartable
import com.android.systemui.dagger.qualifiers.PerUser
@@ -67,4 +68,9 @@ interface CommunalStartableModule {
@IntoMap
@ClassKey(CommunalMetricsStartable::class)
fun bindCommunalMetricsStartable(impl: CommunalMetricsStartable): CoreStartable
+
+ @Binds
+ @IntoMap
+ @ClassKey(DevicePosturingCommandListener::class)
+ fun bindDevicePosturingCommandListener(impl: DevicePosturingCommandListener): CoreStartable
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 7ebe52f3bd58..c02784dfab1b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -31,6 +31,7 @@ import com.android.systemui.BootCompleteCache;
import com.android.systemui.BootCompleteCacheImpl;
import com.android.systemui.CameraProtectionModule;
import com.android.systemui.CoreStartable;
+import com.android.systemui.KairosCoreStartableModule;
import com.android.systemui.SystemUISecondaryUserService;
import com.android.systemui.activity.ActivityManagerModule;
import com.android.systemui.ambient.dagger.AmbientModule;
@@ -232,6 +233,7 @@ import javax.inject.Named;
FlagsModule.class,
FlagDependenciesModule.class,
FooterActionsModule.class,
+ KairosCoreStartableModule.class,
GestureModule.class,
InputMethodModule.class,
KeyEventRepositoryModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt
index 6c6d730819f3..911327a0bd18 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt
@@ -17,10 +17,10 @@
package com.android.systemui.deviceentry.domain.interactor
import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor
-import com.android.systemui.biometrics.shared.model.SensorLocation
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
+import com.android.systemui.shared.customization.data.SensorLocation
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt
index 7d684cab39f7..5e3b2ae0b59f 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt
@@ -132,8 +132,6 @@ constructor(
DeviceEntryRestrictionReason.UnattendedUpdate
authFlags.isPrimaryAuthRequiredAfterTimeout ->
DeviceEntryRestrictionReason.SecurityTimeout
- authFlags.isPrimaryAuthRequiredAfterLockout ->
- DeviceEntryRestrictionReason.BouncerLockedOut
isFingerprintLockedOut ->
DeviceEntryRestrictionReason.StrongBiometricsLockedOut
isFaceLockedOut && faceAuthInteractor.isFaceAuthStrong() ->
@@ -376,8 +374,7 @@ constructor(
private val interactor: DeviceUnlockedInteractor,
) : CoreStartable {
override fun start() {
- if (!SceneContainerFlag.isEnabled)
- return
+ if (!SceneContainerFlag.isEnabled) return
applicationScope.launch { interactor.activate() }
}
diff --git a/packages/SystemUI/src/com/android/systemui/education/ContextualEducationMetricsLogger.kt b/packages/SystemUI/src/com/android/systemui/education/ContextualEducationMetricsLogger.kt
index 9af259a9b642..d10958a2ce4a 100644
--- a/packages/SystemUI/src/com/android/systemui/education/ContextualEducationMetricsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/ContextualEducationMetricsLogger.kt
@@ -42,8 +42,8 @@ class ContextualEducationMetricsLogger @Inject constructor() {
}
SysUiStatsLog.write(
SysUiStatsLog.CONTEXTUAL_EDUCATION_TRIGGERED,
- statsGestureType,
statsEducationType,
+ statsGestureType,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionKeyTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionKeyTutorialScreen.kt
index 950a727aedae..0ab5a80e0044 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionKeyTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionKeyTutorialScreen.kt
@@ -25,6 +25,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
+import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
@@ -45,7 +46,10 @@ import com.android.systemui.res.R
fun ActionKeyTutorialScreen(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) {
BackHandler(onBack = onBack)
val screenConfig = buildScreenConfig()
- var actionState: TutorialActionState by remember { mutableStateOf(NotStarted) }
+ var actionState: TutorialActionState by
+ rememberSaveable(stateSaver = TutorialActionState.stateSaver()) {
+ mutableStateOf(NotStarted)
+ }
val focusRequester = remember { FocusRequester() }
Box(
modifier =
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt
index c40adfe6baf8..21afa40c441b 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt
@@ -33,10 +33,13 @@ import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
+import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
+import androidx.compose.runtime.saveable.Saver
+import androidx.compose.runtime.saveable.mapSaver
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
@@ -45,11 +48,13 @@ import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
+import com.android.compose.windowsizeclass.LocalWindowSizeClass
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.Error
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.Finished
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.InProgress
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.InProgressAfterError
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.NotStarted
+import com.android.systemui.keyboard.shortcut.ui.composable.hasCompactWindowSize
sealed interface TutorialActionState {
data object NotStarted : TutorialActionState
@@ -66,6 +71,31 @@ sealed interface TutorialActionState {
data class InProgressAfterError(val inProgress: InProgress) :
TutorialActionState, Progress by inProgress
+
+ companion object {
+ fun stateSaver(): Saver<TutorialActionState, Any> {
+ val classKey = "class"
+ val successAnimationKey = "animation"
+ return mapSaver(
+ save = {
+ buildMap {
+ put(classKey, it::class.java.name)
+ if (it is Finished) put(successAnimationKey, it.successAnimation)
+ }
+ },
+ restore = { map ->
+ when (map[classKey] as? String) {
+ NotStarted::class.java.name,
+ InProgress::class.java.name -> NotStarted
+ Error::class.java.name,
+ InProgressAfterError::class.java.name -> Error
+ Finished::class.java.name -> Finished(map[successAnimationKey]!! as Int)
+ else -> NotStarted
+ }
+ },
+ )
+ }
+ }
}
interface Progress {
@@ -82,18 +112,25 @@ fun ActionTutorialContent(
) {
Column(
verticalArrangement = Arrangement.Center,
- modifier =
- Modifier.fillMaxSize()
- .background(config.colors.background)
- .safeDrawingPadding()
- .padding(start = 48.dp, top = 100.dp, end = 48.dp, bottom = 8.dp),
+ modifier = Modifier.fillMaxSize().background(config.colors.background).safeDrawingPadding(),
) {
+ val isCompactWindow = hasCompactWindowSize()
when (LocalConfiguration.current.orientation) {
Configuration.ORIENTATION_LANDSCAPE -> {
- HorizontalDescriptionAndAnimation(actionState, config, Modifier.weight(1f))
+ HorizontalDescriptionAndAnimation(
+ actionState,
+ config,
+ isCompactWindow,
+ Modifier.weight(1f),
+ )
}
else -> {
- VerticalDescriptionAndAnimation(actionState, config, Modifier.weight(1f))
+ VerticalDescriptionAndAnimation(
+ actionState,
+ config,
+ isCompactWindow,
+ Modifier.weight(1f),
+ )
}
}
val buttonAlpha by animateFloatAsState(if (actionState is Finished) 1f else 0f)
@@ -109,11 +146,15 @@ fun ActionTutorialContent(
private fun HorizontalDescriptionAndAnimation(
actionState: TutorialActionState,
config: TutorialScreenConfig,
+ isCompactWindow: Boolean,
modifier: Modifier = Modifier,
) {
- Row(modifier = modifier.fillMaxWidth()) {
- TutorialDescription(actionState, config, modifier = Modifier.weight(1f))
- Spacer(modifier = Modifier.width(70.dp))
+ Row(
+ modifier =
+ modifier.fillMaxWidth().padding(start = 48.dp, top = 100.dp, end = 48.dp, bottom = 8.dp)
+ ) {
+ TutorialDescription(actionState, config, isCompactWindow, modifier = Modifier.weight(1f))
+ Spacer(modifier = Modifier.width(24.dp))
TutorialAnimation(actionState, config, modifier = Modifier.weight(1f))
}
}
@@ -122,20 +163,25 @@ private fun HorizontalDescriptionAndAnimation(
private fun VerticalDescriptionAndAnimation(
actionState: TutorialActionState,
config: TutorialScreenConfig,
+ isCompactWindow: Boolean,
modifier: Modifier = Modifier,
) {
- Column(modifier = modifier.fillMaxWidth().padding(horizontal = 40.dp, vertical = 40.dp)) {
- Spacer(modifier = Modifier.weight(0.1f))
+ val horizontalPadding = if (isCompactWindow) 24.dp else 96.dp
+ // Represents the majority of tablets in portrait - we need extra spacer at the top and bottom
+ val isTablet = LocalWindowSizeClass.current.heightSizeClass == WindowHeightSizeClass.Expanded
+ Column(
+ modifier =
+ modifier.fillMaxWidth().padding(start = 0.dp, top = 100.dp, end = 0.dp, bottom = 8.dp)
+ ) {
+ if (isTablet) Spacer(modifier = Modifier.weight(0.3f))
TutorialDescription(
actionState,
config,
- modifier =
- Modifier.weight(0.2f)
- // extra padding to better align with animation which has embedded padding
- .padding(horizontal = 15.dp),
+ isCompactWindow,
+ modifier = Modifier.weight(1f).padding(horizontal = horizontalPadding),
)
- Spacer(modifier = Modifier.width(70.dp))
- TutorialAnimation(actionState, config, modifier = Modifier.weight(1f))
+ TutorialAnimation(actionState, config, modifier = Modifier.weight(1.8f).fillMaxWidth())
+ if (isTablet) Spacer(modifier = Modifier.weight(0.3f))
}
}
@@ -143,6 +189,7 @@ private fun VerticalDescriptionAndAnimation(
fun TutorialDescription(
actionState: TutorialActionState,
config: TutorialScreenConfig,
+ isCompactWindow: Boolean,
modifier: Modifier = Modifier,
) {
val focusRequester = remember { FocusRequester() }
@@ -159,7 +206,9 @@ fun TutorialDescription(
Column(verticalArrangement = Arrangement.Top, modifier = modifier) {
Text(
text = stringResource(id = titleTextId),
- style = MaterialTheme.typography.displayLarge,
+ style =
+ if (isCompactWindow) MaterialTheme.typography.headlineLarge
+ else MaterialTheme.typography.displayMedium,
color = config.colors.title,
modifier = Modifier.focusRequester(focusRequester).focusable(),
)
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialAnimation.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialAnimation.kt
index b0816ce608a0..dc0d7b689d0a 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialAnimation.kt
@@ -131,10 +131,14 @@ private fun SuccessAnimation(
) {
val composition by
rememberLottieComposition(LottieCompositionSpec.RawRes(finishedState.successAnimation))
+ var animationFinished by rememberSaveable(key = "animationFinished") { mutableStateOf(false) }
val progress by animateLottieCompositionAsState(composition, iterations = 1)
+ if (progress == 1f) {
+ animationFinished = true
+ }
LottieAnimation(
composition = composition,
- progress = { progress },
+ progress = { if (animationFinished) 1f else progress },
dynamicProperties = animationProperties,
modifier = Modifier.fillMaxSize(),
)
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 ba31d08c9c1b..bf60c9a52417 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
@@ -105,6 +105,7 @@ import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
+import androidx.compose.ui.text.style.Hyphens
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
@@ -969,7 +970,7 @@ private fun CategoryItemTwoPane(
Text(
fontSize = 18.sp,
color = colors.textColor(selected).value,
- style = MaterialTheme.typography.titleSmall,
+ style = MaterialTheme.typography.titleSmall.copy(hyphens = Hyphens.Auto),
text = label,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
index 7a72732ea6bf..18cabad6b2d5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
@@ -33,6 +33,7 @@ import android.util.Log
import com.android.app.tracing.coroutines.runBlockingTraced as runBlocking
import com.android.systemui.SystemUIAppComponentFactoryBase
import com.android.systemui.SystemUIAppComponentFactoryBase.ContextAvailableCallback
+import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
import com.android.systemui.keyguard.ui.preview.KeyguardRemotePreviewManager
@@ -46,6 +47,7 @@ class CustomizationProvider :
@Inject lateinit var interactor: KeyguardQuickAffordanceInteractor
@Inject lateinit var shadeModeInteractor: ShadeModeInteractor
+ @Inject lateinit var fingerprintPropertyInteractor: FingerprintPropertyInteractor
@Inject lateinit var previewManager: KeyguardRemotePreviewManager
@Inject @Main lateinit var mainDispatcher: CoroutineDispatcher
@@ -345,6 +347,14 @@ class CustomizationProvider :
}
private fun queryRuntimeValues(): Cursor {
+ // If not UDFPS, the udfpsLocation will be null
+ val udfpsLocation =
+ if (fingerprintPropertyInteractor.isUdfps.value) {
+ fingerprintPropertyInteractor.sensorLocation.value
+ } else {
+ null
+ }
+
return MatrixCursor(
arrayOf(
Contract.RuntimeValuesTable.Columns.NAME,
@@ -358,6 +368,9 @@ class CustomizationProvider :
if (shadeModeInteractor.isShadeLayoutWide.value) 1 else 0,
)
)
+ addRow(
+ arrayOf(Contract.RuntimeValuesTable.KEY_UDFPS_LOCATION, udfpsLocation?.encode())
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 647362873015..5baef915ea01 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -3492,7 +3492,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
public void showSurfaceBehindKeyguard() {
mSurfaceBehindRemoteAnimationRequested = true;
- if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) {
+ if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS && !KeyguardWmStateRefactor.isEnabled()) {
startKeyguardTransition(false /* keyguardShowing */, false /* aodShowing */);
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/OWNERS b/packages/SystemUI/src/com/android/systemui/keyguard/OWNERS
index 208a17c0a220..ebe603b7428c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/OWNERS
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/OWNERS
@@ -2,6 +2,8 @@ set noparent
# Bug component: 78010
+include /services/core/java/com/android/server/biometrics/OWNERS
+
amiko@google.com
beverlyt@google.com
bhinegardner@google.com
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
index a74384f61469..df41535ff783 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
@@ -174,25 +174,24 @@ constructor(
if (!isKeyguardGoingAway) {
// Since WM triggered this, we're likely not transitioning to GONE yet. See if we can
// start that transition.
- val startedDismiss =
- keyguardDismissTransitionInteractor.startDismissKeyguardTransition(
- reason = "Going away remote animation started"
- )
-
- if (!startedDismiss) {
- // If the transition wasn't started, we're already GONE. This can happen with timing
- // issues, where the remote animation took a long time to start, and something else
- // caused us to unlock in the meantime. Since we're already GONE, simply end the
- // remote animatiom immediately.
- Log.d(
- TAG,
- "onKeyguardGoingAwayRemoteAnimationStart: " +
- "Dismiss transition was not started; we're already GONE. " +
- "Ending remote animation.",
- )
- finishedCallback.onAnimationFinished()
- return
- }
+ keyguardDismissTransitionInteractor.startDismissKeyguardTransition(
+ reason = "Going away remote animation started",
+ onAlreadyGone = {
+ // Called if we're already GONE by the time the dismiss transition would have
+ // started. This can happen due to timing issues, where the remote animation
+ // took a long time to start, and something else caused us to unlock in the
+ // meantime. Since we're already GONE, simply end the remote animation
+ // immediately.
+ Log.d(
+ TAG,
+ "onKeyguardGoingAwayRemoteAnimationStart: " +
+ "Dismiss transition was not started; we're already GONE. " +
+ "Ending remote animation.",
+ )
+ finishedCallback.onAnimationFinished()
+ isKeyguardGoingAway = false
+ },
+ )
isKeyguardGoingAway = true
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissTransitionInteractor.kt
index 089e5dc42df3..c0a486c005ab 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissTransitionInteractor.kt
@@ -16,23 +16,31 @@
package com.android.systemui.keyguard.domain.interactor
+import android.animation.ValueAnimator
import android.util.Log
import com.android.systemui.Flags.transitionRaceCondition
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
+import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
+import com.android.systemui.keyguard.shared.model.TransitionInfo
+import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
@SysUISingleton
class KeyguardDismissTransitionInteractor
@Inject
constructor(
+ @Background private val scope: CoroutineScope,
private val repository: KeyguardTransitionRepository,
private val fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor,
private val fromPrimaryBouncerTransitionInteractor: FromPrimaryBouncerTransitionInteractor,
@@ -43,45 +51,63 @@ constructor(
) {
/**
- * Called to start a transition that will ultimately dismiss the keyguard from the current
- * state.
+ * Launches a coroutine to start a transition that will ultimately dismiss the keyguard from the
+ * current state.
*
* This is called exclusively by sources that can authoritatively say we should be unlocked,
* including KeyguardSecurityContainerController and WindowManager.
*
- * Returns [false] if the transition was not started, because we're already GONE or we don't
- * know how to dismiss keyguard from the current state.
+ * This is one of the few transitions that is started outside of the From*TransitionInteractor
+ * classes. This is because this is an external call that must be respected, so it doesn't
+ * matter what state we're in/coming from - we must transition from that state to GONE.
+ *
+ * Invokes [onAlreadyGone] if the transition was not started because we're already GONE by the
+ * time the coroutine runs.
*/
- fun startDismissKeyguardTransition(reason: String = ""): Boolean {
- if (SceneContainerFlag.isEnabled) return false
+ @JvmOverloads
+ fun startDismissKeyguardTransition(reason: String = "", onAlreadyGone: (() -> Unit)? = null) {
+ if (SceneContainerFlag.isEnabled) return
Log.d(TAG, "#startDismissKeyguardTransition(reason=$reason)")
- val startedState =
- if (transitionRaceCondition()) {
- repository.currentTransitionInfo.to
+
+ scope.launch {
+ val startedState =
+ if (transitionRaceCondition()) {
+ repository.currentTransitionInfo.to
+ } else {
+ repository.currentTransitionInfoInternal.value.to
+ }
+
+ val animator: ValueAnimator? =
+ when (startedState) {
+ LOCKSCREEN -> fromLockscreenTransitionInteractor
+ PRIMARY_BOUNCER -> fromPrimaryBouncerTransitionInteractor
+ ALTERNATE_BOUNCER -> fromAlternateBouncerTransitionInteractor
+ AOD -> fromAodTransitionInteractor
+ DOZING -> fromDozingTransitionInteractor
+ OCCLUDED -> fromOccludedTransitionInteractor
+ else -> null
+ }?.getDefaultAnimatorForTransitionsToState(KeyguardState.GONE)
+
+ if (startedState != KeyguardState.GONE && animator != null) {
+ repository.startTransition(
+ TransitionInfo(
+ "KeyguardDismissTransitionInteractor" +
+ if (reason.isNotBlank()) "($reason)" else "",
+ startedState,
+ KeyguardState.GONE,
+ animator,
+ TransitionModeOnCanceled.LAST_VALUE,
+ )
+ )
} else {
- repository.currentTransitionInfoInternal.value.to
- }
- when (startedState) {
- LOCKSCREEN -> fromLockscreenTransitionInteractor.dismissKeyguard()
- PRIMARY_BOUNCER -> fromPrimaryBouncerTransitionInteractor.dismissPrimaryBouncer()
- ALTERNATE_BOUNCER -> fromAlternateBouncerTransitionInteractor.dismissAlternateBouncer()
- AOD -> fromAodTransitionInteractor.dismissAod()
- DOZING -> fromDozingTransitionInteractor.dismissFromDozing()
- KeyguardState.OCCLUDED -> fromOccludedTransitionInteractor.dismissFromOccluded()
- KeyguardState.GONE -> {
Log.i(
TAG,
- "Already transitioning to GONE; ignoring startDismissKeyguardTransition.",
+ "Can't transition to GONE from $startedState; " +
+ "ignoring startDismissKeyguardTransition.",
)
- return false
- }
- else -> {
- Log.e(TAG, "We don't know how to dismiss keyguard from state $startedState.")
- return false
+ onAlreadyGone?.invoke()
}
}
-
- return true
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
index 213083db71c9..9c886b228ca9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
@@ -31,6 +31,7 @@ import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
import com.android.systemui.shared.R as sharedR
import kotlinx.coroutines.DisposableHandle
+import kotlinx.coroutines.flow.combine
object KeyguardSmartspaceViewBinder {
@JvmStatic
@@ -43,21 +44,25 @@ object KeyguardSmartspaceViewBinder {
return keyguardRootView.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.CREATED) {
launch("$TAG#clockViewModel.hasCustomWeatherDataDisplay") {
- clockViewModel.hasCustomWeatherDataDisplay.collect { hasCustomWeatherDataDisplay
- ->
- updateDateWeatherToBurnInLayer(
- keyguardRootView,
- clockViewModel,
- smartspaceViewModel,
+ combine(
+ smartspaceViewModel.isWeatherVisible,
+ clockViewModel.hasCustomWeatherDataDisplay,
+ ::Pair,
)
- blueprintInteractor.refreshBlueprint(
- Config(
- Type.SmartspaceVisibility,
- checkPriority = false,
- terminatePrevious = false,
+ .collect {
+ updateDateWeatherToBurnInLayer(
+ keyguardRootView,
+ clockViewModel,
+ smartspaceViewModel,
)
- )
- }
+ blueprintInteractor.refreshBlueprint(
+ Config(
+ Type.SmartspaceVisibility,
+ checkPriority = false,
+ terminatePrevious = false,
+ )
+ )
+ }
}
launch("$TAG#smartspaceViewModel.bcSmartspaceVisibility") {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
index cd038d799f42..9319bc890c6c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
@@ -23,6 +23,8 @@ import android.view.ViewTreeObserver.OnGlobalLayoutListener
import androidx.constraintlayout.widget.Barrier
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
+import androidx.constraintlayout.widget.ConstraintSet.GONE
+import androidx.constraintlayout.widget.ConstraintSet.VISIBLE
import com.android.systemui.customization.R as customR
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
@@ -195,24 +197,13 @@ constructor(
smartspaceController.requestSmartspaceUpdate()
constraintSet.apply {
- val weatherVisibility =
- when (keyguardSmartspaceViewModel.isWeatherVisible.value) {
- true -> ConstraintSet.VISIBLE
- false -> ConstraintSet.GONE
- }
- setVisibility(sharedR.id.weather_smartspace_view, weatherVisibility)
- setAlpha(
- sharedR.id.weather_smartspace_view,
- if (weatherVisibility == View.VISIBLE) 1f else 0f,
- )
- val dateVisibility =
- if (keyguardClockViewModel.hasCustomWeatherDataDisplay.value) ConstraintSet.GONE
- else ConstraintSet.VISIBLE
- setVisibility(sharedR.id.date_smartspace_view, dateVisibility)
- setAlpha(
- sharedR.id.date_smartspace_view,
- if (dateVisibility == ConstraintSet.VISIBLE) 1f else 0f,
- )
+ val showWeather = keyguardSmartspaceViewModel.isWeatherVisible.value
+ setVisibility(sharedR.id.weather_smartspace_view, if (showWeather) VISIBLE else GONE)
+ setAlpha(sharedR.id.weather_smartspace_view, if (showWeather) 1f else 0f)
+
+ val showDateView = !keyguardClockViewModel.hasCustomWeatherDataDisplay.value
+ setVisibility(sharedR.id.date_smartspace_view, if (showDateView) VISIBLE else GONE)
+ setAlpha(sharedR.id.date_smartspace_view, if (showDateView) 1f else 0f)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
index f5e0c81ca9a2..b1a2ec92401a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
@@ -20,7 +20,6 @@ import android.animation.FloatEvaluator
import android.animation.IntEvaluator
import com.android.keyguard.KeyguardViewController
import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor
-import com.android.systemui.biometrics.shared.model.SensorLocation
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
@@ -34,6 +33,7 @@ import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shared.customization.data.SensorLocation
import com.android.systemui.util.kotlin.sample
import dagger.Lazy
import javax.inject.Inject
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 8fe225a8b93f..88fdc83fa7a0 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
@@ -100,7 +100,7 @@ constructor(
keyguardClockInteractor.clockShouldBeCentered.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = false,
+ initialValue = true,
)
// To translate elements below smartspace in weather clock to avoid overlapping between date
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
index 5ee80a7b7442..f8425c16c341 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
@@ -77,7 +77,7 @@ constructor(
isWeatherVisible(
clockIncludesCustomWeatherDisplay =
keyguardClockViewModel.hasCustomWeatherDataDisplay.value,
- isWeatherEnabled = smartspaceInteractor.isWeatherEnabled.value,
+ isWeatherEnabled = isWeatherEnabled.value,
),
)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/Media3ActionFactory.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/Media3ActionFactory.kt
index a6b9442b1270..71c8d1f5b4c7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/Media3ActionFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/Media3ActionFactory.kt
@@ -130,7 +130,7 @@ constructor(
null, // no action to perform when clicked
context.getString(R.string.controls_media_button_connecting),
if (Flags.mediaControlsUiUpdate()) {
- context.getDrawable(R.drawable.ic_media_connecting_status_container)
+ context.getDrawable(R.drawable.ic_media_connecting_button_container)
} else {
context.getDrawable(R.drawable.ic_media_connecting_container)
},
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaActions.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaActions.kt
index 9bf556cf07c2..5fef81f4596a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaActions.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaActions.kt
@@ -71,7 +71,7 @@ fun createActionsFromState(
null, // no action to perform when clicked
context.getString(R.string.controls_media_button_connecting),
if (Flags.mediaControlsUiUpdate()) {
- context.getDrawable(R.drawable.ic_media_connecting_status_container)
+ context.getDrawable(R.drawable.ic_media_connecting_button_container)
} else {
context.getDrawable(R.drawable.ic_media_connecting_container)
},
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/animation/ColorSchemeTransition.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/animation/ColorSchemeTransition.kt
index 21407f3bd6d4..02b403786768 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/animation/ColorSchemeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/animation/ColorSchemeTransition.kt
@@ -27,6 +27,7 @@ import android.graphics.drawable.RippleDrawable
import com.android.internal.R
import com.android.internal.annotations.VisibleForTesting
import com.android.settingslib.Utils
+import com.android.systemui.Flags
import com.android.systemui.media.controls.ui.view.MediaViewHolder
import com.android.systemui.monet.ColorScheme
import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect
@@ -51,7 +52,7 @@ interface ColorTransition {
open class AnimatingColorTransition(
private val defaultColor: Int,
private val extractColor: (ColorScheme) -> Int,
- private val applyColor: (Int) -> Unit
+ private val applyColor: (Int) -> Unit,
) : AnimatorUpdateListener, ColorTransition {
private val argbEvaluator = ArgbEvaluator()
@@ -105,35 +106,52 @@ internal constructor(
private val mediaViewHolder: MediaViewHolder,
private val multiRippleController: MultiRippleController,
private val turbulenceNoiseController: TurbulenceNoiseController,
- animatingColorTransitionFactory: AnimatingColorTransitionFactory
+ animatingColorTransitionFactory: AnimatingColorTransitionFactory,
) {
constructor(
context: Context,
mediaViewHolder: MediaViewHolder,
multiRippleController: MultiRippleController,
- turbulenceNoiseController: TurbulenceNoiseController
+ turbulenceNoiseController: TurbulenceNoiseController,
) : this(
context,
mediaViewHolder,
multiRippleController,
turbulenceNoiseController,
- ::AnimatingColorTransition
+ ::AnimatingColorTransition,
)
+
var loadingEffect: LoadingEffect? = null
- val bgColor = context.getColor(com.google.android.material.R.color.material_dynamic_neutral20)
+ val bgColor =
+ if (Flags.mediaControlsUiUpdate()) {
+ context.getColor(R.color.materialColorOnSurface)
+ } else {
+ context.getColor(com.google.android.material.R.color.material_dynamic_neutral20)
+ }
+
+ val textColor = context.getColor(R.color.materialColorInverseOnSurface)
+ val buttonBgColor = context.getColor(R.color.materialColorPrimary)
+ val insideButtonColor = context.getColor(R.color.materialColorOnPrimary)
+
val surfaceColor =
animatingColorTransitionFactory(bgColor, ::surfaceFromScheme) { surfaceColor ->
val colorList = ColorStateList.valueOf(surfaceColor)
- mediaViewHolder.seamlessIcon.imageTintList = colorList
- mediaViewHolder.seamlessText.setTextColor(surfaceColor)
mediaViewHolder.albumView.backgroundTintList = colorList
mediaViewHolder.gutsViewHolder.setSurfaceColor(surfaceColor)
+
+ if (Flags.mediaControlsUiUpdate()) return@animatingColorTransitionFactory
+ mediaViewHolder.seamlessIcon.imageTintList = colorList
+ mediaViewHolder.seamlessText.setTextColor(surfaceColor)
}
val accentPrimary =
animatingColorTransitionFactory(
- loadDefaultColor(R.attr.textColorPrimary),
- ::accentPrimaryFromScheme
+ if (Flags.mediaControlsUiUpdate()) {
+ buttonBgColor
+ } else {
+ loadDefaultColor(R.attr.textColorPrimary)
+ },
+ ::accentPrimaryFromScheme,
) { accentPrimary ->
val accentColorList = ColorStateList.valueOf(accentPrimary)
mediaViewHolder.actionPlayPause.backgroundTintList = accentColorList
@@ -145,8 +163,12 @@ internal constructor(
val accentSecondary =
animatingColorTransitionFactory(
- loadDefaultColor(R.attr.textColorPrimary),
- ::accentSecondaryFromScheme
+ if (Flags.mediaControlsUiUpdate()) {
+ buttonBgColor
+ } else {
+ loadDefaultColor(R.attr.textColorPrimary)
+ },
+ ::accentSecondaryFromScheme,
) { accentSecondary ->
val colorList = ColorStateList.valueOf(accentSecondary)
(mediaViewHolder.seamlessButton.background as? RippleDrawable)?.let {
@@ -157,7 +179,11 @@ internal constructor(
val colorSeamless =
animatingColorTransitionFactory(
- loadDefaultColor(R.attr.textColorPrimary),
+ if (Flags.mediaControlsUiUpdate()) {
+ buttonBgColor
+ } else {
+ loadDefaultColor(R.attr.textColorPrimary)
+ },
{ colorScheme: ColorScheme ->
// A1-100 dark in dark theme, A1-200 in light theme
if (
@@ -170,13 +196,17 @@ internal constructor(
{ seamlessColor: Int ->
val accentColorList = ColorStateList.valueOf(seamlessColor)
mediaViewHolder.seamlessButton.backgroundTintList = accentColorList
- }
+ },
)
val textPrimary =
animatingColorTransitionFactory(
- loadDefaultColor(R.attr.textColorPrimary),
- ::textPrimaryFromScheme
+ if (Flags.mediaControlsUiUpdate()) {
+ textColor
+ } else {
+ loadDefaultColor(R.attr.textColorPrimary)
+ },
+ ::textPrimaryFromScheme,
) { textPrimary ->
mediaViewHolder.titleText.setTextColor(textPrimary)
val textColorList = ColorStateList.valueOf(textPrimary)
@@ -192,25 +222,41 @@ internal constructor(
val textPrimaryInverse =
animatingColorTransitionFactory(
- loadDefaultColor(R.attr.textColorPrimaryInverse),
- ::textPrimaryInverseFromScheme
+ if (Flags.mediaControlsUiUpdate()) {
+ insideButtonColor
+ } else {
+ loadDefaultColor(R.attr.textColorPrimaryInverse)
+ },
+ ::textPrimaryInverseFromScheme,
) { textPrimaryInverse ->
- mediaViewHolder.actionPlayPause.imageTintList =
- ColorStateList.valueOf(textPrimaryInverse)
+ val colorList = ColorStateList.valueOf(textPrimaryInverse)
+ mediaViewHolder.actionPlayPause.imageTintList = colorList
+
+ if (!Flags.mediaControlsUiUpdate()) return@animatingColorTransitionFactory
+ mediaViewHolder.seamlessIcon.imageTintList = colorList
+ mediaViewHolder.seamlessText.setTextColor(textPrimaryInverse)
}
val textSecondary =
animatingColorTransitionFactory(
- loadDefaultColor(R.attr.textColorSecondary),
- ::textSecondaryFromScheme
+ if (Flags.mediaControlsUiUpdate()) {
+ textColor
+ } else {
+ loadDefaultColor(R.attr.textColorSecondary)
+ },
+ ::textSecondaryFromScheme,
) { textSecondary ->
mediaViewHolder.artistText.setTextColor(textSecondary)
}
val textTertiary =
animatingColorTransitionFactory(
- loadDefaultColor(R.attr.textColorTertiary),
- ::textTertiaryFromScheme
+ if (Flags.mediaControlsUiUpdate()) {
+ textColor
+ } else {
+ loadDefaultColor(R.attr.textColorTertiary)
+ },
+ ::textTertiaryFromScheme,
) { textTertiary ->
mediaViewHolder.seekBar.progressBackgroundTintList =
ColorStateList.valueOf(textTertiary)
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 4e97eb5bc9d1..47161191b229 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
@@ -1744,7 +1744,8 @@ constructor(
println("location: $desiredLocation")
println(
"state: ${desiredHostState?.expansion}, " +
- "only active ${desiredHostState?.showsOnlyActiveMedia}"
+ "only active ${desiredHostState?.showsOnlyActiveMedia}, " +
+ "visible ${desiredHostState?.visible}"
)
println("isSwipedAway: ${MediaPlayerData.isSwipedAway}")
println("allowMediaPlayerOnLockScreen: $allowMediaPlayerOnLockScreen")
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt
index b4dabbe036e9..a6aa159692ec 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt
@@ -37,12 +37,14 @@ import com.android.app.animation.Interpolators
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.app.tracing.traceSection
import com.android.keyguard.KeyguardViewController
+import com.android.systemui.Dumpable
import com.android.systemui.Flags.mediaControlsLockscreenShadeBugFix
import com.android.systemui.communal.ui.viewmodel.CommunalTransitionViewModel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dreams.DreamOverlayStateController
+import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.media.controls.domain.pipeline.MediaDataManager
@@ -62,6 +64,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.statusbar.policy.SplitShadeStateController
import com.android.systemui.util.animation.UniqueObjectHostView
import com.android.systemui.util.settings.SecureSettings
+import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -119,7 +122,8 @@ constructor(
@Application private val coroutineScope: CoroutineScope,
private val splitShadeStateController: SplitShadeStateController,
private val logger: MediaViewLogger,
-) {
+ private val dumpManager: DumpManager,
+) : Dumpable {
/** Track the media player setting status on lock screen. */
private var allowMediaPlayerOnLockScreen: Boolean = true
@@ -476,6 +480,7 @@ constructor(
}
init {
+ dumpManager.registerNormalDumpable(TAG, this)
updateConfiguration()
configurationController.addCallback(
object : ConfigurationController.ConfigurationListener {
@@ -1344,6 +1349,19 @@ constructor(
return isCommunalShowing && !isPrimaryBouncerShowing && !isAnyShadeFullyExpanded
}
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ pw.apply {
+ println(
+ "current attachment: $currentAttachmentLocation, " +
+ "desired location: $desiredLocation, " +
+ "visible ${getHost(desiredLocation)?.visible}"
+ )
+ println("previous location: $previousLocation")
+ println("bounds: $currentBounds, target $targetBounds")
+ println("clipping: $currentClipping, target $targetClipping")
+ }
+ }
+
companion object {
/** Attached in expanded quick settings */
const val LOCATION_QS = 0
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt
index a2ddc20844e7..86e92941256b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt
@@ -883,7 +883,6 @@ constructor(
currentEndLocation = endLocation
currentStartLocation = startLocation
currentTransitionProgress = transitionProgress
- logger.logMediaLocation("setCurrentState", startLocation, endLocation)
val shouldAnimate = animateNextStateChange && !applyImmediately
@@ -900,6 +899,7 @@ constructor(
// If the view isn't bound, we can drop the animation, otherwise we'll execute it
animateNextStateChange = false
if (transitionLayout == null) {
+ logger.logMediaLocation("setCurrentState: view not bound", startLocation, endLocation)
return
}
@@ -949,7 +949,7 @@ constructor(
)
}
logger.logMediaSize(
- "setCurrentState (progress $transitionProgress)",
+ "setCurrentState $startLocation -> $endLocation (progress $transitionProgress)",
result.width,
result.height,
)
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginEnablerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginEnablerImpl.java
index 40f59744e038..7f1c7a525f97 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginEnablerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginEnablerImpl.java
@@ -18,6 +18,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.shared.plugins.PluginEnabler;
@@ -28,6 +29,7 @@ import javax.inject.Singleton;
/** */
@Singleton
public class PluginEnablerImpl implements PluginEnabler {
+ private static final String TAG = "PluginEnablerImpl";
private static final String CRASH_DISABLED_PLUGINS_PREF_FILE = "auto_disabled_plugins_prefs";
private final PackageManager mPm;
@@ -64,8 +66,13 @@ public class PluginEnablerImpl implements PluginEnabler {
@Override
public boolean isEnabled(ComponentName component) {
- return mPm.getComponentEnabledSetting(component)
- != PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+ try {
+ return mPm.getComponentEnabledSetting(component)
+ != PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+ } catch (IllegalArgumentException ex) {
+ Log.e(TAG, "Package Manager Exception", ex);
+ return false;
+ }
}
@Override
@@ -73,6 +80,6 @@ public class PluginEnablerImpl implements PluginEnabler {
if (isEnabled(componentName)) {
return ENABLED;
}
- return mAutoDisabledPrefs.getInt(componentName.flattenToString(), DISABLED_MANUALLY);
+ return mAutoDisabledPrefs.getInt(componentName.flattenToString(), DISABLED_UNKNOWN);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/BuildTextView.kt b/packages/SystemUI/src/com/android/systemui/qs/BuildTextView.kt
new file mode 100644
index 000000000000..1f864e9d7b8b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/BuildTextView.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.accessibility.AccessibilityNodeInfo
+import com.android.systemui.res.R
+import com.android.systemui.util.DelayableMarqueeTextView
+
+class BuildTextView
+@JvmOverloads
+constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+ defStyleRes: Int = 0,
+) : DelayableMarqueeTextView(context, attrs, defStyleAttr, defStyleRes) {
+
+ override fun onInitializeAccessibilityNodeInfo(info: AccessibilityNodeInfo?) {
+ super.onInitializeAccessibilityNodeInfo(info)
+ // Clear selected state so it's not announced by accessibility, but we can still marquee.
+ info?.isSelected = false
+ info?.addAction(
+ AccessibilityNodeInfo.AccessibilityAction(
+ AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK.id,
+ resources.getString(R.string.copy_to_clipboard_a11y_action),
+ )
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
index 56fece8ecf5c..b53685ee3cd4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
@@ -88,11 +88,11 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.android.compose.animation.scene.ContentKey
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.ElementMatcher
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
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.animation.scene.transitions
@@ -100,6 +100,7 @@ import com.android.compose.modifiers.height
import com.android.compose.modifiers.padding
import com.android.compose.modifiers.thenIf
import com.android.compose.theme.PlatformTheme
+import com.android.mechanics.GestureContext
import com.android.systemui.Dumpable
import com.android.systemui.brightness.ui.compose.BrightnessSliderContainer
import com.android.systemui.compose.modifiers.sysuiResTag
@@ -579,7 +580,7 @@ constructor(
}
@Composable
- private fun SceneScope.QuickQuickSettingsElement() {
+ private fun ContentScope.QuickQuickSettingsElement() {
val qqsPadding = viewModel.qqsHeaderHeight
val bottomPadding = viewModel.qqsBottomPadding
DisposableEffect(Unit) {
@@ -663,7 +664,7 @@ constructor(
}
@Composable
- private fun SceneScope.QuickSettingsElement() {
+ private fun ContentScope.QuickSettingsElement() {
val qqsPadding = viewModel.qqsHeaderHeight
val qsExtraPadding = dimensionResource(R.dimen.qs_panel_padding_top)
Column(
@@ -935,6 +936,8 @@ private class ExpansionTransition(currentProgress: Float) :
override val isUserInputOngoing: Boolean
get() = true
+ override val gestureContext: GestureContext? = null
+
private val finishCompletable = CompletableDeferred<Unit>()
override suspend fun run() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModuleBase.kt b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModuleBase.kt
index 3fd87689b169..e2a39160defc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModuleBase.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModuleBase.kt
@@ -54,11 +54,11 @@ interface QSModuleBase {
/** A map of internal QS tiles. Ensures that this can be injected even if it is empty */
@Multibinds fun tileMap(): Map<String?, QSTileImpl<*>?>?
- @Binds fun bindsQsSceneAdapter(impl: QSSceneAdapterImpl?): QSSceneAdapter?
+ @Binds fun bindsQsSceneAdapter(impl: QSSceneAdapterImpl): QSSceneAdapter
/** Dims the screen */
@Binds
fun bindReduceBrightColorsController(
- impl: ReduceBrightColorsControllerImpl?
- ): ReduceBrightColorsController?
+ impl: ReduceBrightColorsControllerImpl
+ ): ReduceBrightColorsController
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
index a22eb3a8d517..185ea93387a3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
@@ -18,7 +18,7 @@ package com.android.systemui.qs.panels.ui.compose
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.systemui.qs.panels.shared.model.SizedTile
import com.android.systemui.qs.panels.shared.model.TileRow
import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
@@ -27,7 +27,7 @@ import com.android.systemui.qs.pipeline.shared.TileSpec
/** A layout of tiles, indicating how they should be composed when showing in QS or in edit mode. */
interface GridLayout {
- @Composable fun SceneScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier)
+ @Composable fun ContentScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier)
@Composable
fun EditTileGrid(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
index 39408d3dee72..c72381f45239 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
@@ -40,7 +40,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.pointerInteropFilter
import androidx.compose.ui.unit.dp
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.modifiers.padding
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.development.ui.compose.BuildNumber
@@ -63,7 +63,7 @@ constructor(
@PaginatedBaseLayoutType private val delegateGridLayout: PaginatableGridLayout,
) : GridLayout by delegateGridLayout {
@Composable
- override fun SceneScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier) {
+ override fun ContentScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier) {
val viewModel =
rememberViewModel(traceName = "PaginatedGridLayout-TileGrid") {
viewModelFactory.create()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
index 8fda23d54625..5cb30b999e13 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
@@ -27,7 +27,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.util.fastMap
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.grid.ui.compose.VerticalSpannedGrid
import com.android.systemui.qs.composefragment.ui.GridAnchor
@@ -38,7 +38,7 @@ import com.android.systemui.qs.shared.ui.ElementKeys.toElementKey
import com.android.systemui.res.R
@Composable
-fun SceneScope.QuickQuickSettings(
+fun ContentScope.QuickQuickSettings(
viewModel: QuickQuickSettingsViewModel,
modifier: Modifier = Modifier,
) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
index 6c1906bb906f..bcc44d397eb2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
@@ -20,11 +20,11 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.systemui.qs.panels.ui.viewmodel.TileGridViewModel
@Composable
-fun SceneScope.TileGrid(viewModel: TileGridViewModel, modifier: Modifier = Modifier) {
+fun ContentScope.TileGrid(viewModel: TileGridViewModel, modifier: Modifier = Modifier) {
val gridLayout by viewModel.gridLayout.collectAsStateWithLifecycle()
val tiles by viewModel.tileViewModels.collectAsStateWithLifecycle(emptyList())
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
index 66961b6efe46..4432d336237f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
@@ -26,7 +26,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.util.fastMap
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.grid.ui.compose.VerticalSpannedGrid
import com.android.systemui.haptics.msdl.qs.TileHapticsViewModelFactoryProvider
@@ -58,7 +58,7 @@ constructor(
) : PaginatableGridLayout {
@Composable
- override fun SceneScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier) {
+ override fun ContentScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier) {
DisposableEffect(tiles) {
val token = Any()
tiles.forEach { it.startListening(token) }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/BaseAutoAddableModule.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/BaseAutoAddableModule.kt
index e1ec338cec6f..a6edb586776b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/BaseAutoAddableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/BaseAutoAddableModule.kt
@@ -27,7 +27,6 @@ import com.android.systemui.qs.pipeline.domain.autoaddable.DataSaverAutoAddable
import com.android.systemui.qs.pipeline.domain.autoaddable.DeviceControlsAutoAddable
import com.android.systemui.qs.pipeline.domain.autoaddable.HotspotAutoAddable
import com.android.systemui.qs.pipeline.domain.autoaddable.NightDisplayAutoAddable
-import com.android.systemui.qs.pipeline.domain.autoaddable.ReduceBrightColorsAutoAddable
import com.android.systemui.qs.pipeline.domain.autoaddable.WalletAutoAddable
import com.android.systemui.qs.pipeline.domain.autoaddable.WorkTileAutoAddable
import com.android.systemui.qs.pipeline.domain.model.AutoAddable
@@ -45,11 +44,11 @@ interface BaseAutoAddableModule {
@ElementsIntoSet
fun providesAutoAddableSetting(
@Main resources: Resources,
- autoAddableSettingFactory: AutoAddableSetting.Factory
+ autoAddableSettingFactory: AutoAddableSetting.Factory,
): Set<AutoAddable> {
return AutoAddableSettingList.parseSettingsResource(
resources,
- autoAddableSettingFactory
+ autoAddableSettingFactory,
)
.toSet()
}
@@ -75,10 +74,6 @@ interface BaseAutoAddableModule {
@Binds @IntoSet fun bindNightDisplayAutoAddable(impl: NightDisplayAutoAddable): AutoAddable
- @Binds
- @IntoSet
- fun bindReduceBrightColorsAutoAddable(impl: ReduceBrightColorsAutoAddable): AutoAddable
-
@Binds @IntoSet fun bindWalletAutoAddable(impl: WalletAutoAddable): AutoAddable
@Binds @IntoSet fun bindWorkModeAutoAddable(impl: WorkTileAutoAddable): AutoAddable
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/A11yShortcutAutoAddableList.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/A11yShortcutAutoAddableList.kt
index a0c9737de0ee..791339c75eeb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/A11yShortcutAutoAddableList.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/A11yShortcutAutoAddableList.kt
@@ -16,7 +16,6 @@
package com.android.systemui.qs.pipeline.domain.autoaddable
-import android.view.accessibility.Flags
import com.android.internal.accessibility.AccessibilityShortcutController
import com.android.systemui.qs.pipeline.domain.model.AutoAddable
import com.android.systemui.qs.pipeline.shared.TileSpec
@@ -33,31 +32,27 @@ object A11yShortcutAutoAddableList {
* accessibility features with shortcut options
*/
fun getA11yShortcutAutoAddables(factory: A11yShortcutAutoAddable.Factory): Set<AutoAddable> {
- return if (Flags.a11yQsShortcut()) {
- setOf(
- factory.create(
- TileSpec.create(ColorCorrectionTile.TILE_SPEC),
- AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME
- ),
- factory.create(
- TileSpec.create(ColorInversionTile.TILE_SPEC),
- AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME
- ),
- factory.create(
- TileSpec.create(OneHandedModeTile.TILE_SPEC),
- AccessibilityShortcutController.ONE_HANDED_COMPONENT_NAME
- ),
- factory.create(
- TileSpec.create(ReduceBrightColorsTile.TILE_SPEC),
- AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_COMPONENT_NAME
- ),
- factory.create(
- TileSpec.create(HearingDevicesTile.TILE_SPEC),
- AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME
- )
- )
- } else {
- emptySet()
- }
+ return setOf(
+ factory.create(
+ TileSpec.create(ColorCorrectionTile.TILE_SPEC),
+ AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME,
+ ),
+ factory.create(
+ TileSpec.create(ColorInversionTile.TILE_SPEC),
+ AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME,
+ ),
+ factory.create(
+ TileSpec.create(OneHandedModeTile.TILE_SPEC),
+ AccessibilityShortcutController.ONE_HANDED_COMPONENT_NAME,
+ ),
+ factory.create(
+ TileSpec.create(ReduceBrightColorsTile.TILE_SPEC),
+ AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_COMPONENT_NAME,
+ ),
+ factory.create(
+ TileSpec.create(HearingDevicesTile.TILE_SPEC),
+ AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME,
+ ),
+ )
}
}
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
deleted file mode 100644
index bde682074780..000000000000
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddable.kt
+++ /dev/null
@@ -1,72 +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.qs.pipeline.domain.autoaddable
-
-import android.view.accessibility.Flags
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.qs.ReduceBrightColorsController
-import com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE
-import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
-import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
-import com.android.systemui.qs.pipeline.shared.TileSpec
-import com.android.systemui.qs.tiles.ReduceBrightColorsTile
-import javax.inject.Inject
-import javax.inject.Named
-import kotlinx.coroutines.channels.ProducerScope
-
-/**
- * [AutoAddable] for [ReduceBrightColorsTile.TILE_SPEC].
- *
- * It will send a signal to add the tile when reduce bright colors is enabled.
- */
-@SysUISingleton
-class ReduceBrightColorsAutoAddable
-@Inject
-constructor(
- controller: ReduceBrightColorsController,
- @Named(RBC_AVAILABLE) private var available: Boolean,
-) :
- CallbackControllerAutoAddable<
- ReduceBrightColorsController.Listener,
- ReduceBrightColorsController,
- >(controller) {
-
- override val spec: TileSpec
- get() = TileSpec.create(ReduceBrightColorsTile.TILE_SPEC)
-
- override fun ProducerScope<AutoAddSignal>.getCallback(): ReduceBrightColorsController.Listener {
- return object : ReduceBrightColorsController.Listener {
- override fun onActivated(activated: Boolean) {
- if (activated && available) {
- sendAdd()
- }
- }
- }
- }
-
- override val autoAddTracking
- get() =
- if (Flags.a11yQsShortcut()) {
- AutoAddTracking.Disabled
- } else if (available) {
- super.autoAddTracking
- } else {
- AutoAddTracking.Disabled
- }
-
- override val description = "ReduceBrightColorsAutoAddable ($autoAddTracking)"
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/AccessibilityTilesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/AccessibilityTilesInteractor.kt
index 56c3e0e648bf..481d1e3c28bd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/AccessibilityTilesInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/AccessibilityTilesInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.qs.pipeline.domain.interactor
import android.content.Context
-import android.view.accessibility.Flags
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.accessibility.data.repository.AccessibilityQsShortcutsRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -30,7 +30,6 @@ import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collectLatest
-import com.android.app.tracing.coroutines.launchTraced as launch
/** Observe the tiles in the QS Panel and perform accessibility related actions */
@SysUISingleton
@@ -48,10 +47,7 @@ constructor(
if (!initialized.compareAndSet(/* expectedValue= */ false, /* newValue= */ true)) {
return
}
-
- if (Flags.a11yQsShortcut()) {
- startObservingTiles(currentTilesInteractor)
- }
+ startObservingTiles(currentTilesInteractor)
}
private fun startObservingTiles(currentTilesInteractor: CurrentTilesInteractor) {
@@ -63,14 +59,11 @@ constructor(
.collectLatest {
a11yQsShortcutsRepository.notifyAccessibilityManagerTilesChanged(
it.userContext,
- it.currentTileSpecs
+ it.currentTileSpecs,
)
}
}
}
- private data class Data(
- val currentTileSpecs: List<TileSpec>,
- val userContext: Context,
- )
+ private data class Data(val currentTileSpecs: List<TileSpec>, val userContext: Context)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
index 74563fff8775..22b742f2f05b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
@@ -29,7 +29,6 @@ import android.widget.Button;
import androidx.annotation.Nullable;
import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.Flags;
import com.android.systemui.accessibility.hearingaid.HearingDevicesChecker;
import com.android.systemui.accessibility.hearingaid.HearingDevicesDialogManager;
import com.android.systemui.animation.Expandable;
@@ -138,9 +137,4 @@ public class HearingDevicesTile extends QSTileImpl<BooleanState> {
public CharSequence getTileLabel() {
return mContext.getString(R.string.quick_settings_hearing_devices_label);
}
-
- @Override
- public boolean isAvailable() {
- return Flags.hearingAidsQsTileDialog();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
index e93cec875429..42b35c736d42 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
@@ -191,8 +191,9 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState>
@Override
public boolean getDetailsViewModel(Consumer<TileDetailsViewModel> callback) {
- handleClick(() ->
- callback.accept(new ScreenRecordDetailsViewModel())
+ handleClick(() -> executeWhenUnlockedKeyguard(
+ () -> callback.accept(new ScreenRecordDetailsViewModel(mController,
+ this::onStartRecordingClicked)))
);
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ScreenRecordDetailsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ScreenRecordDetailsViewModel.kt
index 42cb1248ccff..54e4a521c239 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ScreenRecordDetailsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ScreenRecordDetailsViewModel.kt
@@ -17,27 +17,45 @@
package com.android.systemui.qs.tiles.dialog
import android.view.LayoutInflater
+import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.heightIn
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import com.android.systemui.plugins.qs.TileDetailsViewModel
import com.android.systemui.res.R
+import com.android.systemui.screenrecord.RecordingController
+import com.android.systemui.screenrecord.ScreenRecordPermissionViewBinder
/** The view model used for the screen record details view in the Quick Settings */
-class ScreenRecordDetailsViewModel() : TileDetailsViewModel() {
+class ScreenRecordDetailsViewModel(
+ private val recordingController: RecordingController,
+ private val onStartRecordingClicked: Runnable,
+) : TileDetailsViewModel() {
+
+ private var viewBinder: ScreenRecordPermissionViewBinder =
+ recordingController.createScreenRecordPermissionViewBinder(onStartRecordingClicked)
+
@Composable
override fun GetContentView() {
// TODO(b/378514312): Finish implementing this function.
+
+ if (recordingController.isScreenCaptureDisabled) {
+ // TODO(b/388345506): Show disabled page here.
+ return
+ }
+
AndroidView(
- modifier = Modifier.fillMaxWidth().heightIn(max = VIEW_MAX_HEIGHT),
+ modifier = Modifier.fillMaxWidth().fillMaxHeight(),
factory = { context ->
// Inflate with the existing dialog xml layout
- LayoutInflater.from(context).inflate(R.layout.screen_share_dialog, null)
+ val view = LayoutInflater.from(context).inflate(R.layout.screen_share_dialog, null)
+ viewBinder.bind(view)
+
+ view
+ // TODO(b/378514473): Revamp the details view according to the spec.
},
+ onRelease = { viewBinder.unbind() },
)
}
@@ -54,8 +72,4 @@ class ScreenRecordDetailsViewModel() : TileDetailsViewModel() {
// No sub-title in this tile.
return ""
}
-
- companion object {
- private val VIEW_MAX_HEIGHT: Dp = 320.dp
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/interactor/HearingDevicesTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/interactor/HearingDevicesTileDataInteractor.kt
index ec0a4e9db896..33b7feb49b09 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/interactor/HearingDevicesTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/interactor/HearingDevicesTileDataInteractor.kt
@@ -17,7 +17,6 @@
package com.android.systemui.qs.tiles.impl.hearingdevices.domain.interactor
import android.os.UserHandle
-import com.android.systemui.Flags
import com.android.systemui.accessibility.hearingaid.HearingDevicesChecker
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
@@ -62,8 +61,7 @@ constructor(
.flowOn(backgroundContext)
.distinctUntilChanged()
- override fun availability(user: UserHandle): Flow<Boolean> =
- flowOf(Flags.hearingAidsQsTileDialog())
+ override fun availability(user: UserHandle): Flow<Boolean> = flowOf(true)
private fun getModel() =
HearingDevicesTileModel(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModel.kt
index c0c0aea073f1..465d08b36ed0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModel.kt
@@ -17,13 +17,14 @@
package com.android.systemui.qs.ui.viewmodel
import androidx.compose.runtime.getValue
-import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
+import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackAppearanceInteractor
+import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.awaitCancellation
@@ -44,6 +45,7 @@ class QuickSettingsShadeOverlayContentViewModel
constructor(
val shadeInteractor: ShadeInteractor,
val sceneInteractor: SceneInteractor,
+ val notificationStackAppearanceInteractor: NotificationStackAppearanceInteractor,
val shadeHeaderViewModelFactory: ShadeHeaderViewModel.Factory,
quickSettingsContainerViewModelFactory: QuickSettingsContainerViewModel.Factory,
) : ExclusiveActivatable() {
@@ -92,6 +94,11 @@ constructor(
awaitCancellation()
}
+ /** Notifies that the bounds of the QuickSettings panel have changed. */
+ fun onPanelShapeChanged(shape: ShadeScrimShape?) {
+ notificationStackAppearanceInteractor.setQsPanelShape(shape)
+ }
+
fun onScrimClicked() {
shadeInteractor.collapseQuickSettingsShade(loggingReason = "shade scrim clicked")
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index e3cf41191384..adf9eb44e162 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -58,6 +58,7 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.PatternMatcher;
import android.os.Process;
@@ -146,7 +147,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
public static final String TAG_OPS = "OverviewProxyService";
private static final long BACKOFF_MILLIS = 1000;
private static final long DEFERRED_CALLBACK_MILLIS = 5000;
-
// Max backoff caps at 5 mins
private static final long MAX_BACKOFF_MILLIS = 10 * 60 * 1000;
@@ -183,6 +183,10 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
private int mConnectionBackoffAttempts;
private boolean mBound;
private boolean mIsEnabled;
+ // This is set to false when the overview service is requested to be bound until it is notified
+ // that the previous service has been cleaned up in IOverviewProxy#onUnbind(). It is also set to
+ // true after a 1000ms timeout by mDeferredBindAfterTimedOutCleanup.
+ private boolean mIsPrevServiceCleanedUp = true;
private boolean mIsSystemOrVisibleBgUser;
private int mCurrentBoundedUserId = -1;
@@ -489,6 +493,12 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
retryConnectionWithBackoff();
};
+ private final Runnable mDeferredBindAfterTimedOutCleanup = () -> {
+ Log.w(TAG_OPS, "Timed out waiting for previous service to clean up, binding to new one");
+ mIsPrevServiceCleanedUp = true;
+ maybeBindService();
+ };
+
private final BroadcastReceiver mUserEventReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -859,6 +869,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
mShadeViewControllerLazy.get().cancelInputFocusTransfer();
});
}
+ mIsPrevServiceCleanedUp = true;
startConnectionToCurrentUser();
}
@@ -889,6 +900,19 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
}
mHandler.removeCallbacks(mConnectionRunnable);
+ maybeBindService();
+ }
+
+ private void maybeBindService() {
+ if (!mIsPrevServiceCleanedUp) {
+ Log.w(TAG_OPS, "Skipping connection to TouchInteractionService until previous"
+ + " instance is cleaned up.");
+ if (!mHandler.hasCallbacks(mDeferredConnectionCallback)) {
+ mHandler.postDelayed(mDeferredBindAfterTimedOutCleanup, BACKOFF_MILLIS);
+ }
+ return;
+ }
+
// Avoid creating TouchInteractionService because the System user in HSUM mode does not
// interact with UI elements
UserHandle currentUser = UserHandle.of(mUserTracker.getUserId());
@@ -907,6 +931,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
Log.e(TAG_OPS, "Unable to bind because of security error", e);
}
if (mBound) {
+ mIsPrevServiceCleanedUp = false;
// Ensure that connection has been established even if it thinks it is bound
mHandler.postDelayed(mDeferredConnectionCallback, DEFERRED_CALLBACK_MILLIS);
} else {
@@ -960,6 +985,24 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
// Always unbind the service (ie. if called through onNullBinding or onBindingDied)
mContext.unbindService(mOverviewServiceConnection);
mBound = false;
+ if (mOverviewProxy != null) {
+ try {
+ mOverviewProxy.onUnbind(new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle data) throws RemoteException {
+ // Received Launcher reply, try to bind anew.
+ mIsPrevServiceCleanedUp = true;
+ if (mHandler.hasCallbacks(mDeferredBindAfterTimedOutCleanup)) {
+ mHandler.removeCallbacks(mDeferredBindAfterTimedOutCleanup);
+ maybeBindService();
+ }
+ }
+ });
+ } catch (RemoteException e) {
+ Log.w(TAG_OPS, "disconnectFromLauncherService failed to notify Launcher");
+ mIsPrevServiceCleanedUp = true;
+ }
+ }
}
if (mOverviewProxy != null) {
@@ -1189,6 +1232,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
pw.print(" mInputFocusTransferStartMillis="); pw.println(mInputFocusTransferStartMillis);
pw.print(" mActiveNavBarRegion="); pw.println(mActiveNavBarRegion);
pw.print(" mNavBarMode="); pw.println(mNavBarMode);
+ pw.print(" mIsPrevServiceCleanedUp="); pw.println(mIsPrevServiceCleanedUp);
mSysUiState.dump(pw, args);
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 3a23a71cf7bf..8657c1723507 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -94,7 +94,6 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.distinctUntilChangedBy
-import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.filterNot
@@ -717,14 +716,7 @@ constructor(
}
applicationScope.launch {
- keyguardInteractor.isAodAvailable
- .flatMapLatest { isAodAvailable ->
- if (!isAodAvailable) {
- powerInteractor.detailedWakefulness
- } else {
- emptyFlow()
- }
- }
+ powerInteractor.detailedWakefulness
.distinctUntilChangedBy { it.isAwake() }
.collect { wakefulness ->
when {
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
index 9ee99e45ceeb..140fbf340f8b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
@@ -70,6 +70,8 @@ public class RecordingController
private final ScreenCaptureDisabledDialogDelegate mScreenCaptureDisabledDialogDelegate;
private final ScreenRecordPermissionDialogDelegate.Factory
mScreenRecordPermissionDialogDelegateFactory;
+ private final ScreenRecordPermissionViewBinder.Factory
+ mScreenRecordPermissionViewBinderFactory;
protected static final String INTENT_UPDATE_STATE =
"com.android.systemui.screenrecord.UPDATE_STATE";
@@ -118,7 +120,8 @@ public class RecordingController
MediaProjectionMetricsLogger mediaProjectionMetricsLogger,
ScreenCaptureDisabledDialogDelegate screenCaptureDisabledDialogDelegate,
ScreenRecordPermissionDialogDelegate.Factory
- screenRecordPermissionDialogDelegateFactory) {
+ screenRecordPermissionDialogDelegateFactory,
+ ScreenRecordPermissionViewBinder.Factory screenRecordPermissionViewBinderFactory) {
mMainExecutor = mainExecutor;
mDevicePolicyResolver = devicePolicyResolver;
mBroadcastDispatcher = broadcastDispatcher;
@@ -127,6 +130,7 @@ public class RecordingController
mMediaProjectionMetricsLogger = mediaProjectionMetricsLogger;
mScreenCaptureDisabledDialogDelegate = screenCaptureDisabledDialogDelegate;
mScreenRecordPermissionDialogDelegateFactory = screenRecordPermissionDialogDelegateFactory;
+ mScreenRecordPermissionViewBinderFactory = screenRecordPermissionViewBinderFactory;
BroadcastOptions options = BroadcastOptions.makeBasic();
options.setInteractive(true);
@@ -151,8 +155,7 @@ public class RecordingController
* If screen capturing is currently not allowed it will return a dialog
* that warns users about it. */
public Dialog createScreenRecordDialog(@Nullable Runnable onStartRecordingClicked) {
- if (mDevicePolicyResolver.get()
- .isScreenCaptureCompletelyDisabled(getHostUserHandle())) {
+ if (isScreenCaptureDisabled()) {
return mScreenCaptureDisabledDialogDelegate.createSysUIDialog();
}
@@ -165,6 +168,27 @@ public class RecordingController
}
/**
+ * Create a view binder that controls the logic of views inside the screen record permission
+ * view.
+ * @param onStartRecordingClicked the callback that is run when the start button is clicked.
+ */
+ public ScreenRecordPermissionViewBinder createScreenRecordPermissionViewBinder(
+ @Nullable Runnable onStartRecordingClicked
+ ) {
+ return mScreenRecordPermissionViewBinderFactory
+ .create(getHostUserHandle(), getHostUid(), this,
+ onStartRecordingClicked);
+ }
+
+ /**
+ * Check if screen capture is currently disabled for this device and user.
+ */
+ public boolean isScreenCaptureDisabled() {
+ return mDevicePolicyResolver.get()
+ .isScreenCaptureCompletelyDisabled(getHostUserHandle());
+ }
+
+ /**
* Start counting down in preparation to start a recording
* @param ms Total time in ms to wait before starting
* @param interval Time in ms per countdown step
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionViewBinder.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionViewBinder.kt
index 9fcb3dfc0ad3..23df1c5441bf 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionViewBinder.kt
@@ -49,6 +49,9 @@ import com.android.systemui.mediaprojection.permission.ScreenShareOption
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.res.R
import com.android.systemui.settings.UserContextProvider
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
class ScreenRecordPermissionViewBinder(
private val hostUserHandle: UserHandle,
@@ -68,6 +71,38 @@ class ScreenRecordPermissionViewBinder(
mediaProjectionMetricsLogger,
defaultSelectedMode,
) {
+ @AssistedInject
+ constructor(
+ @Assisted hostUserHandle: UserHandle,
+ @Assisted hostUid: Int,
+ mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
+ displayManager: DisplayManager,
+ @Assisted controller: RecordingController,
+ activityStarter: ActivityStarter,
+ userContextProvider: UserContextProvider,
+ @Assisted onStartRecordingClicked: Runnable?,
+ ) : this(
+ hostUserHandle,
+ hostUid,
+ mediaProjectionMetricsLogger,
+ defaultSelectedMode = SINGLE_APP,
+ displayManager,
+ controller,
+ activityStarter,
+ userContextProvider,
+ onStartRecordingClicked,
+ )
+
+ @AssistedFactory
+ interface Factory {
+ fun create(
+ hostUserHandle: UserHandle,
+ hostUid: Int,
+ recordingController: RecordingController,
+ onStartRecordingClicked: Runnable?,
+ ): ScreenRecordPermissionViewBinder
+ }
+
private lateinit var tapsSwitch: Switch
private lateinit var audioSwitch: Switch
private lateinit var tapsView: View
diff --git a/packages/SystemUI/src/com/android/systemui/shade/OWNERS b/packages/SystemUI/src/com/android/systemui/shade/OWNERS
index 5b8277284117..89454b84a528 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/OWNERS
+++ b/packages/SystemUI/src/com/android/systemui/shade/OWNERS
@@ -1,5 +1,7 @@
justinweir@google.com
syeonlee@google.com
+nicomazz@google.com
+burakov@google.com
per-file *Notification* = set noparent
per-file *Notification* = file:../statusbar/notification/OWNERS
@@ -9,13 +11,13 @@ per-file NotificationsQSContainerController.kt = kozynski@google.com, asc@google
per-file *ShadeHeader* = syeonlee@google.com, kozynski@google.com, asc@google.com
per-file *Interactor* = set noparent
-per-file *Interactor* = justinweir@google.com, syeonlee@google.com, nijamkin@google.com
+per-file *Interactor* = justinweir@google.com, syeonlee@google.com, nijamkin@google.com, nicomazz@google.com, burakov@google.com
per-file *Repository* = set noparent
-per-file *Repository* = justinweir@google.com, syeonlee@google.com, nijamkin@google.com
+per-file *Repository* = justinweir@google.com, syeonlee@google.com, nijamkin@google.com, nicomazz@google.com, burakov@google.com
-per-file NotificationShadeWindow* = pixel@google.com, cinek@google.com, juliacr@google.com, justinweir@google.com, syeonlee@google.com
+per-file NotificationShadeWindow* = pixel@google.com, cinek@google.com, juliacr@google.com, justinweir@google.com, syeonlee@google.com, nicomazz@google.com, burakov@google.com
per-file NotificationPanelUnfoldAnimationController.kt = alexflo@google.com, jeffdq@google.com, juliacr@google.com
-per-file NotificationPanelView.java = pixel@google.com, cinek@google.com, juliacr@google.com, justinweir@google.com, syeonlee@google.com
-per-file NotificationPanelViewController.java = pixel@google.com, cinek@google.com, juliacr@google.com, justinweir@google.com, syeonlee@google.com
+per-file NotificationPanelView.java = pixel@google.com, cinek@google.com, juliacr@google.com, justinweir@google.com, syeonlee@google.com, nicomazz@google.com, burakov@google.com
+per-file NotificationPanelViewController.java = pixel@google.com, cinek@google.com, juliacr@google.com, justinweir@google.com, syeonlee@google.com, nicomazz@google.com, burakov@google.com
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTracker.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTracker.kt
index e358dcec8b10..ec9bba7c1f0f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTracker.kt
@@ -95,7 +95,7 @@ constructor(
*/
@Synchronized
fun onShadeDisplayChanging(displayId: Int) {
- previousJob?.cancel(CancellationException("New shade move in progress"))
+ previousJob?.cancel(CancellationException("New shade move in progress to $displayId"))
previousJob = bgScope.launch { onShadeDisplayChangingAsync(displayId) }
}
@@ -109,8 +109,8 @@ constructor(
val reason =
when (e) {
is CancellationException ->
- "Shade move cancelled as a new move is being done " +
- "before the previous one finished."
+ "Shade move to $displayId cancelled as a new move is being done " +
+ "before the previous one finished. Message: ${e.message}"
else -> "Shade move cancelled."
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt b/packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt
index 17b5e5b584b4..d53f9f7ec595 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt
@@ -16,6 +16,7 @@
package com.android.systemui.shade.display
+import com.android.systemui.shade.domain.interactor.ShadeExpandedStateInteractor.ShadeElement
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoSet
@@ -33,11 +34,33 @@ interface ShadeDisplayPolicy {
val displayId: StateFlow<Int>
}
+/** Return the latest element the user intended to expand in the shade (notifications or QS). */
+interface ShadeExpansionIntent {
+ /**
+ * Returns the latest element the user intended to expand in the shade (notifications or QS).
+ *
+ * When the shade moves to a different display (e.g., due to a touch on the status bar of an
+ * external display), it's first collapsed and then re-expanded on the target display.
+ *
+ * If the user was trying to open a specific element (QS or notifications) when the shade was on
+ * the original display, that intention might be lost during the collapse/re-expand transition.
+ * This is used to preserve the user's intention, ensuring the correct element is expanded on
+ * the target display.
+ *
+ * Note that the expansion intent is kept for a very short amount of time (ideally, just a bit
+ * above the time it takes for the shade to collapse)
+ */
+ fun consumeExpansionIntent(): ShadeElement?
+}
+
@Module
interface ShadeDisplayPolicyModule {
@Binds fun provideDefaultPolicy(impl: StatusBarTouchShadeDisplayPolicy): ShadeDisplayPolicy
+ @Binds
+ fun provideShadeExpansionIntent(impl: StatusBarTouchShadeDisplayPolicy): ShadeExpansionIntent
+
@IntoSet
@Binds
fun provideDefaultDisplayPolicyToSet(impl: DefaultDisplayShadePolicy): ShadeDisplayPolicy
diff --git a/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt b/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt
index 30b086f03d66..91020aa7bdb0 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt
@@ -18,16 +18,25 @@ package com.android.systemui.shade.display
import android.util.Log
import android.view.Display
+import android.view.MotionEvent
import com.android.app.tracing.coroutines.launchTraced
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.display.data.repository.DisplayRepository
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.shade.ShadeOnDefaultDisplayWhenLocked
+import com.android.systemui.shade.domain.interactor.NotificationShadeElement
+import com.android.systemui.shade.domain.interactor.QSShadeElement
+import com.android.systemui.shade.domain.interactor.ShadeExpandedStateInteractor.ShadeElement
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
+import dagger.Lazy
+import java.util.concurrent.atomic.AtomicReference
import javax.inject.Inject
+import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -49,14 +58,20 @@ class StatusBarTouchShadeDisplayPolicy
constructor(
displayRepository: DisplayRepository,
keyguardRepository: KeyguardRepository,
- @Background val backgroundScope: CoroutineScope,
- @ShadeOnDefaultDisplayWhenLocked val shadeOnDefaultDisplayWhenLocked: Boolean,
-) : ShadeDisplayPolicy {
+ @Background private val backgroundScope: CoroutineScope,
+ @ShadeOnDefaultDisplayWhenLocked private val shadeOnDefaultDisplayWhenLocked: Boolean,
+ private val shadeInteractor: Lazy<ShadeInteractor>,
+ private val qsShadeElement: Lazy<QSShadeElement>,
+ private val notificationElement: Lazy<NotificationShadeElement>,
+) : ShadeDisplayPolicy, ShadeExpansionIntent {
override val name: String = "status_bar_latest_touch"
private val currentDisplayId = MutableStateFlow(Display.DEFAULT_DISPLAY)
private val availableDisplayIds: StateFlow<Set<Int>> = displayRepository.displayIds
+ private var latestIntent = AtomicReference<ShadeElement?>()
+ private var timeoutJob: Job? = null
+
override val displayId: StateFlow<Int> =
if (shadeOnDefaultDisplayWhenLocked) {
keyguardRepository.isKeyguardShowing
@@ -75,8 +90,29 @@ constructor(
private var removalListener: Job? = null
/** Called when the status bar on the given display is touched. */
- fun onStatusBarTouched(statusBarDisplayId: Int) {
+ fun onStatusBarTouched(event: MotionEvent, statusBarWidth: Int) {
ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
+ updateShadeDisplayIfNeeded(event)
+ updateExpansionIntent(event, statusBarWidth)
+ }
+
+ override fun consumeExpansionIntent(): ShadeElement? {
+ return latestIntent.getAndSet(null)
+ }
+
+ private fun updateExpansionIntent(event: MotionEvent, statusBarWidth: Int) {
+ val element = classifyStatusBarEvent(event, statusBarWidth)
+ latestIntent.set(element)
+ timeoutJob?.cancel()
+ timeoutJob =
+ backgroundScope.launchTraced("StatusBarTouchDisplayPolicy#intentTimeout") {
+ delay(EXPANSION_INTENT_EXPIRY)
+ latestIntent.set(null)
+ }
+ }
+
+ private fun updateShadeDisplayIfNeeded(event: MotionEvent) {
+ val statusBarDisplayId = event.displayId
if (statusBarDisplayId !in availableDisplayIds.value) {
Log.e(TAG, "Got touch on unknown display $statusBarDisplayId")
return
@@ -90,6 +126,17 @@ constructor(
}
}
+ private fun classifyStatusBarEvent(
+ motionEvent: MotionEvent,
+ statusbarWidth: Int,
+ ): ShadeElement {
+ val xPercentage = motionEvent.x / statusbarWidth
+ val threshold = shadeInteractor.get().getTopEdgeSplitFraction()
+ return if (xPercentage < threshold) {
+ notificationElement.get()
+ } else qsShadeElement.get()
+ }
+
private fun monitorDisplayRemovals(): Job {
return backgroundScope.launchTraced("StatusBarTouchDisplayPolicy#monitorDisplayRemovals") {
currentDisplayId.subscriptionCount
@@ -112,5 +159,6 @@ constructor(
private companion object {
const val TAG = "StatusBarTouchDisplayPolicy"
+ val EXPANSION_INTENT_EXPIRY = 2.seconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
index 691a383cb338..fc26499a27a7 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
@@ -30,6 +30,7 @@ import com.android.systemui.shade.ShadeDisplayChangeLatencyTracker
import com.android.systemui.shade.ShadeTraceLogger.logMoveShadeWindowTo
import com.android.systemui.shade.ShadeTraceLogger.traceReparenting
import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
+import com.android.systemui.shade.display.ShadeExpansionIntent
import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
import com.android.window.flags.Flags
import java.util.Optional
@@ -49,6 +50,7 @@ constructor(
@Main private val mainThreadContext: CoroutineContext,
private val shadeDisplayChangeLatencyTracker: ShadeDisplayChangeLatencyTracker,
shadeExpandedInteractor: Optional<ShadeExpandedStateInteractor>,
+ private val shadeExpansionIntent: ShadeExpansionIntent,
) : CoreStartable {
private val shadeExpandedInteractor =
@@ -89,11 +91,10 @@ constructor(
try {
withContext(mainThreadContext) {
traceReparenting {
- shadeDisplayChangeLatencyTracker.onShadeDisplayChanging(destinationId)
- val expandedElement = shadeExpandedInteractor.currentlyExpandedElement.value
- expandedElement?.collapse(reason = "Shade window move")
- reparentToDisplayId(id = destinationId)
- expandedElement?.expand(reason = "Shade window move")
+ collapseAndExpandShadeIfNeeded {
+ shadeDisplayChangeLatencyTracker.onShadeDisplayChanging(destinationId)
+ reparentToDisplayId(id = destinationId)
+ }
checkContextDisplayMatchesExpected(destinationId)
}
}
@@ -106,6 +107,18 @@ constructor(
}
}
+ private suspend fun collapseAndExpandShadeIfNeeded(wrapped: () -> Unit) {
+ val previouslyExpandedElement = shadeExpandedInteractor.currentlyExpandedElement.value
+ previouslyExpandedElement?.collapse(reason = COLLAPSE_EXPAND_REASON)
+
+ wrapped()
+
+ // If the user was trying to expand a specific shade element, let's make sure to expand
+ // that one. Otherwise, we can just re-expand the previous expanded element.
+ shadeExpansionIntent.consumeExpansionIntent()?.expand(COLLAPSE_EXPAND_REASON)
+ ?: previouslyExpandedElement?.expand(reason = COLLAPSE_EXPAND_REASON)
+ }
+
private fun checkContextDisplayMatchesExpected(destinationId: Int) {
if (shadeContext.displayId != destinationId) {
Log.wtf(
@@ -125,5 +138,6 @@ constructor(
private companion object {
const val TAG = "ShadeDisplaysInteractor"
+ const val COLLAPSE_EXPAND_REASON = "Shade window move"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractor.kt
index dd3abeec5a72..aba5a6bceb10 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeExpandedStateInteractor.kt
@@ -16,6 +16,7 @@
package com.android.systemui.shade.domain.interactor
+import android.util.Log
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.scene.shared.flag.SceneContainerFlag
@@ -24,6 +25,8 @@ import com.android.systemui.shade.domain.interactor.ShadeExpandedStateInteractor
import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.util.kotlin.Utils.Companion.combineState
import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
@@ -31,7 +34,7 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.withContext
-import kotlinx.coroutines.withTimeout
+import kotlinx.coroutines.withTimeoutOrNull
/**
* Wrapper around [ShadeInteractor] to facilitate expansion and collapse of Notifications and quick
@@ -47,7 +50,7 @@ interface ShadeExpandedStateInteractor {
val currentlyExpandedElement: StateFlow<ShadeElement?>
/** An element from the shade window that can be expanded or collapsed. */
- abstract class ShadeElement {
+ sealed class ShadeElement {
/** Expands the shade element, returning when the expansion is done */
abstract suspend fun expand(reason: String)
@@ -56,17 +59,18 @@ interface ShadeExpandedStateInteractor {
}
}
+private val EXPAND_COLLAPSE_TIMEOUT: Duration = 1.seconds
+
@SysUISingleton
class ShadeExpandedStateInteractorImpl
@Inject
constructor(
- private val shadeInteractor: ShadeInteractor,
+ shadeInteractor: ShadeInteractor,
@Background private val bgScope: CoroutineScope,
+ private val notificationElement: NotificationShadeElement,
+ private val qsElement: QSShadeElement,
) : ShadeExpandedStateInteractor {
- private val notificationElement = NotificationElement()
- private val qsElement = QSElement()
-
override val currentlyExpandedElement: StateFlow<ShadeElement?> =
if (SceneContainerFlag.isEnabled) {
combineState(
@@ -84,35 +88,54 @@ constructor(
} else {
MutableStateFlow(null)
}
+}
- inner class NotificationElement : ShadeElement() {
- override suspend fun expand(reason: String) {
- shadeInteractor.expandNotificationsShade(reason)
- shadeInteractor.shadeExpansion.waitUntil(1f)
+private suspend fun StateFlow<Float>.waitUntil(f: Float, coroutineContext: CoroutineContext) {
+ // it's important to not do this in the main thread otherwise it will block any rendering.
+ withContext(coroutineContext) {
+ withTimeoutOrNull(EXPAND_COLLAPSE_TIMEOUT) {
+ traceWaitForExpansion(expansion = f) { first { it == f } }
}
+ ?: Log.e(
+ "ShadeExpStateInteractor",
+ "Timed out after ${EXPAND_COLLAPSE_TIMEOUT.inWholeMilliseconds}ms while waiting " +
+ "for expansion to match $f. Current one: $value",
+ )
+ }
+}
- override suspend fun collapse(reason: String) {
- shadeInteractor.collapseNotificationsShade(reason)
- shadeInteractor.shadeExpansion.waitUntil(0f)
- }
+@SysUISingleton
+class NotificationShadeElement
+@Inject
+constructor(
+ private val shadeInteractor: ShadeInteractor,
+ @Background private val bgContext: CoroutineContext,
+) : ShadeElement() {
+ override suspend fun expand(reason: String) {
+ shadeInteractor.expandNotificationsShade(reason)
+ shadeInteractor.shadeExpansion.waitUntil(1f, bgContext)
}
- inner class QSElement : ShadeElement() {
- override suspend fun expand(reason: String) {
- shadeInteractor.expandQuickSettingsShade(reason)
- shadeInteractor.qsExpansion.waitUntil(1f)
- }
+ override suspend fun collapse(reason: String) {
+ shadeInteractor.collapseNotificationsShade(reason)
+ shadeInteractor.shadeExpansion.waitUntil(0f, bgContext)
+ }
+}
- override suspend fun collapse(reason: String) {
- shadeInteractor.collapseQuickSettingsShade(reason)
- shadeInteractor.qsExpansion.waitUntil(0f)
- }
+@SysUISingleton
+class QSShadeElement
+@Inject
+constructor(
+ private val shadeInteractor: ShadeInteractor,
+ @Background private val bgContext: CoroutineContext,
+) : ShadeElement() {
+ override suspend fun expand(reason: String) {
+ shadeInteractor.expandQuickSettingsShade(reason)
+ shadeInteractor.qsExpansion.waitUntil(1f, bgContext)
}
- private suspend fun StateFlow<Float>.waitUntil(f: Float) {
- // it's important to not do this in the main thread otherwise it will block any rendering.
- withContext(bgScope.coroutineContext) {
- withTimeout(1.seconds) { traceWaitForExpansion(expansion = f) { first { it == f } } }
- }
+ override suspend fun collapse(reason: String) {
+ shadeInteractor.collapseQuickSettingsShade(reason)
+ shadeInteractor.qsExpansion.waitUntil(0f, bgContext)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ImmersiveModeConfirmation.java b/packages/SystemUI/src/com/android/systemui/statusbar/ImmersiveModeConfirmation.java
index 5ef5a7d2139c..fed3f6e81130 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ImmersiveModeConfirmation.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ImmersiveModeConfirmation.java
@@ -22,8 +22,6 @@ import static android.app.StatusBarManager.DISABLE_BACK;
import static android.app.StatusBarManager.DISABLE_HOME;
import static android.app.StatusBarManager.DISABLE_RECENT;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.ViewRootImpl.CLIENT_IMMERSIVE_CONFIRMATION;
-import static android.view.ViewRootImpl.CLIENT_TRANSIENT;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
import static android.window.DisplayAreaOrganizer.KEY_ROOT_DISPLAY_AREA_ID;
@@ -90,8 +88,8 @@ import kotlin.Lazy;
import javax.inject.Inject;
/**
- * Helper to manage showing/hiding a confirmation prompt when the navigation bar is hidden
- * entering immersive mode.
+ * Helper to manage showing/hiding a confirmation prompt when the navigation bar is hidden
+ * entering immersive mode.
*/
public class ImmersiveModeConfirmation implements CoreStartable, CommandQueue.Callbacks,
TaskStackChangeListener {
@@ -140,9 +138,9 @@ public class ImmersiveModeConfirmation implements CoreStartable, CommandQueue.Ca
@Inject
public ImmersiveModeConfirmation(Context context, CommandQueue commandQueue,
- SecureSettings secureSettings,
- dagger.Lazy<ViewCapture> daggerLazyViewCapture,
- @Background Handler backgroundHandler) {
+ SecureSettings secureSettings,
+ dagger.Lazy<ViewCapture> daggerLazyViewCapture,
+ @Background Handler backgroundHandler) {
mSysUiContext = context;
final Display display = mSysUiContext.getDisplay();
mDisplayContext = display.getDisplayId() == DEFAULT_DISPLAY
@@ -213,7 +211,7 @@ public class ImmersiveModeConfirmation implements CoreStartable, CommandQueue.Ca
public void immersiveModeChanged(int rootDisplayAreaId, boolean isImmersiveMode) {
mHandler.removeMessages(H.SHOW);
if (isImmersiveMode) {
- if (DEBUG) Log.d(TAG, "immersiveModeChanged() sConfirmed=" + sConfirmed);
+ if (DEBUG) Log.d(TAG, "immersiveModeChanged() sConfirmed=" + sConfirmed);
boolean userSetupComplete = (mSecureSettings.getIntForUser(
Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0);
@@ -284,6 +282,7 @@ public class ImmersiveModeConfirmation implements CoreStartable, CommandQueue.Ca
| WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
| WindowManager.LayoutParams.PRIVATE_FLAG_IMMERSIVE_CONFIRMATION_WINDOW;
lp.setTitle("ImmersiveModeConfirmation");
+ lp.accessibilityTitle = mSysUiContext.getString(R.string.immersive_cling_title);
lp.windowAnimations = com.android.internal.R.style.Animation_ImmersiveModeConfirmation;
lp.token = getWindowToken();
return lp;
@@ -313,44 +312,42 @@ public class ImmersiveModeConfirmation implements CoreStartable, CommandQueue.Ca
@Override
public void start() {
- if (CLIENT_TRANSIENT || CLIENT_IMMERSIVE_CONFIRMATION) {
- mCommandQueue.addCallback(this);
-
- final Resources r = mSysUiContext.getResources();
- mShowDelayMs = r.getInteger(R.integer.dock_enter_exit_duration) * 3L;
- mCanSystemBarsBeShownByUser = !r.getBoolean(
- R.bool.config_remoteInsetsControllerControlsSystemBars) || r.getBoolean(
- R.bool.config_remoteInsetsControllerSystemBarsCanBeShownByUserAction);
- IVrManager vrManager = IVrManager.Stub.asInterface(
- ServiceManager.getService(Context.VR_SERVICE));
- if (vrManager != null) {
- try {
- mVrModeEnabled = vrManager.getVrModeState();
- vrManager.registerListener(mVrStateCallbacks);
- mVrStateCallbacks.onVrStateChanged(mVrModeEnabled);
- } catch (RemoteException e) {
- // Ignore, we cannot do anything if we failed to access vr manager.
- }
- }
- TaskStackChangeListeners.getInstance().registerTaskStackListener(this);
- mContentObserver = new ContentObserver(mBackgroundHandler) {
- @Override
- public void onChange(boolean selfChange) {
- onSettingChanged(mSysUiContext.getUserId());
- }
- };
+ mCommandQueue.addCallback(this);
- // Register to listen for changes in Settings.Secure settings.
- mSecureSettings.registerContentObserverForUserSync(
- Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS, mContentObserver,
- UserHandle.USER_CURRENT);
- mSecureSettings.registerContentObserverForUserSync(
- Settings.Secure.USER_SETUP_COMPLETE, mContentObserver,
- UserHandle.USER_CURRENT);
- mBackgroundHandler.post(() -> {
- loadSetting(UserHandle.USER_CURRENT);
- });
+ final Resources r = mSysUiContext.getResources();
+ mShowDelayMs = r.getInteger(R.integer.dock_enter_exit_duration) * 3L;
+ mCanSystemBarsBeShownByUser = !r.getBoolean(
+ R.bool.config_remoteInsetsControllerControlsSystemBars) || r.getBoolean(
+ R.bool.config_remoteInsetsControllerSystemBarsCanBeShownByUserAction);
+ IVrManager vrManager = IVrManager.Stub.asInterface(
+ ServiceManager.getService(Context.VR_SERVICE));
+ if (vrManager != null) {
+ try {
+ mVrModeEnabled = vrManager.getVrModeState();
+ vrManager.registerListener(mVrStateCallbacks);
+ mVrStateCallbacks.onVrStateChanged(mVrModeEnabled);
+ } catch (RemoteException e) {
+ // Ignore, we cannot do anything if we failed to access vr manager.
+ }
}
+ TaskStackChangeListeners.getInstance().registerTaskStackListener(this);
+ mContentObserver = new ContentObserver(mBackgroundHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ onSettingChanged(mSysUiContext.getUserId());
+ }
+ };
+
+ // Register to listen for changes in Settings.Secure settings.
+ mSecureSettings.registerContentObserverForUserSync(
+ Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS, mContentObserver,
+ UserHandle.USER_CURRENT);
+ mSecureSettings.registerContentObserverForUserSync(
+ Settings.Secure.USER_SETUP_COMPLETE, mContentObserver,
+ UserHandle.USER_CURRENT);
+ mBackgroundHandler.post(() -> {
+ loadSetting(UserHandle.USER_CURRENT);
+ });
}
private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
@@ -541,7 +538,7 @@ public class ImmersiveModeConfirmation implements CoreStartable, CommandQueue.Ca
/**
* Returns options that specify the {@link RootDisplayArea} to attach the confirmation window.
- * {@code null} if the {@code rootDisplayAreaId} is {@link FEATURE_UNDEFINED}.
+ * {@code null} if the {@code rootDisplayAreaId} is {@link FEATURE_UNDEFINED}.
*/
@Nullable
private Bundle getOptionsForWindowContext(int rootDisplayAreaId) {
@@ -599,10 +596,7 @@ public class ImmersiveModeConfirmation implements CoreStartable, CommandQueue.Ca
@Override
public void handleMessage(Message msg) {
- if (!CLIENT_TRANSIENT && !CLIENT_IMMERSIVE_CONFIRMATION) {
- return;
- }
- switch(msg.what) {
+ switch (msg.what) {
case SHOW:
handleShow(msg.arg1);
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index 2ed168aa82e8..2157d754ce87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -486,11 +486,6 @@ public final class KeyboardShortcuts {
R.string.keyboard_shortcut_group_system_shortcuts_helper),
KeyEvent.KEYCODE_SLASH,
KeyEvent.META_META_ON));
- systemGroup.addItem(new KeyboardShortcutInfo(
- mContext.getString(
- R.string.keyboard_shortcut_group_system_switch_input),
- KeyEvent.KEYCODE_SPACE,
- KeyEvent.META_META_ON));
return systemGroup;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
index 86954d569199..4fb8f724c971 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
@@ -30,7 +30,9 @@ import com.android.systemui.res.R
import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
import com.android.systemui.statusbar.chips.StatusBarChipsLog
import com.android.systemui.statusbar.chips.call.domain.interactor.CallChipInteractor
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
import com.android.systemui.statusbar.chips.ui.model.ColorsModel
+import com.android.systemui.statusbar.chips.ui.model.ColorsModel.Companion.toCustomColorsModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel
@@ -76,13 +78,20 @@ constructor(
OngoingActivityChipModel.ChipIcon.SingleColorIcon(phoneIcon)
}
+ val colors =
+ if (StatusBarNotifChips.isEnabled && state.promotedContent != null) {
+ state.promotedContent.toCustomColorsModel()
+ } else {
+ ColorsModel.Themed
+ }
+
// This block mimics OngoingCallController#updateChip.
if (state.startTimeMs <= 0L) {
// If the start time is invalid, don't show a timer and show just an
// icon. See b/192379214.
OngoingActivityChipModel.Shown.IconOnly(
icon = icon,
- colors = ColorsModel.Themed,
+ colors = colors,
getOnClickListener(state),
)
} else {
@@ -91,7 +100,7 @@ constructor(
systemClock.elapsedRealtime()
OngoingActivityChipModel.Shown.Timer(
icon = icon,
- colors = ColorsModel.Themed,
+ colors = colors,
startTimeMs = startTimeInElapsedRealtime,
getOnClickListener(state),
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt
index 2121f94caced..4fad01d9f448 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt
@@ -28,6 +28,7 @@ import com.android.systemui.statusbar.chips.StatusBarChipsLog
import com.android.systemui.statusbar.chips.notification.domain.model.NotificationChipModel
import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
+import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor.Companion.isOngoingCallNotification
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
@@ -41,6 +42,7 @@ import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
/** An interactor for the notification chips shown in the status bar. */
@SysUISingleton
@@ -88,45 +90,56 @@ constructor(
private val promotedNotificationInteractors =
MutableStateFlow<List<SingleNotificationChipInteractor>>(emptyList())
+ /**
+ * The notifications that are promoted and ongoing.
+ *
+ * Explicitly does *not* include any ongoing call notifications, even if the call notifications
+ * meet the promotion criteria. Those call notifications will be handled by
+ * [com.android.systemui.statusbar.chips.call.domain.CallChipInteractor] instead. See
+ * b/388521980.
+ */
+ private val promotedOngoingNotifications =
+ activeNotificationsInteractor.promotedOngoingNotifications.map { notifs ->
+ notifs.filterNot { it.isOngoingCallNotification() }
+ }
+
override fun start() {
if (!StatusBarNotifChips.isEnabled) {
return
}
backgroundScope.launch("StatusBarNotificationChipsInteractor") {
- activeNotificationsInteractor.promotedOngoingNotifications
- .pairwise(initialValue = emptyList())
- .collect { (oldNotifs, currentNotifs) ->
- val removedNotifKeys =
- oldNotifs.map { it.key }.minus(currentNotifs.map { it.key }.toSet())
- removedNotifKeys.forEach { removedNotifKey ->
- val wasRemoved = promotedNotificationInteractorMap.remove(removedNotifKey)
- if (wasRemoved == null) {
- logger.w({
- "Attempted to remove $str1 from interactor map but it wasn't present"
- }) {
- str1 = removedNotifKey
- }
+ promotedOngoingNotifications.pairwise(initialValue = emptyList()).collect {
+ (oldNotifs, currentNotifs) ->
+ val removedNotifKeys =
+ oldNotifs.map { it.key }.minus(currentNotifs.map { it.key }.toSet())
+ removedNotifKeys.forEach { removedNotifKey ->
+ val wasRemoved = promotedNotificationInteractorMap.remove(removedNotifKey)
+ if (wasRemoved == null) {
+ logger.w({
+ "Attempted to remove $str1 from interactor map but it wasn't present"
+ }) {
+ str1 = removedNotifKey
}
}
+ }
- currentNotifs.forEach { notif ->
- val interactor =
- promotedNotificationInteractorMap.computeIfAbsent(notif.key) {
- singleNotificationChipInteractorFactory.create(
- notif,
- creationTime = systemClock.currentTimeMillis(),
- )
- }
- interactor.setNotification(notif)
- }
- logger.d({ "Interactors: $str1" }) {
- str1 =
- promotedNotificationInteractorMap.keys.joinToString(separator = " /// ")
- }
- promotedNotificationInteractors.value =
- promotedNotificationInteractorMap.values.toList()
+ currentNotifs.forEach { notif ->
+ val interactor =
+ promotedNotificationInteractorMap.computeIfAbsent(notif.key) {
+ singleNotificationChipInteractorFactory.create(
+ notif,
+ creationTime = systemClock.currentTimeMillis(),
+ )
+ }
+ interactor.setNotification(notif)
}
+ logger.d({ "Interactors: $str1" }) {
+ str1 = promotedNotificationInteractorMap.keys.joinToString(separator = " /// ")
+ }
+ promotedNotificationInteractors.value =
+ promotedNotificationInteractorMap.values.toList()
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
index ec3a5b271e35..18b0dee1c08f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
@@ -23,7 +23,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.statusbar.chips.notification.domain.interactor.StatusBarNotificationChipsInteractor
import com.android.systemui.statusbar.chips.notification.domain.model.NotificationChipModel
import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
-import com.android.systemui.statusbar.chips.ui.model.ColorsModel
+import com.android.systemui.statusbar.chips.ui.model.ColorsModel.Companion.toCustomColorsModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor
@@ -72,11 +72,7 @@ constructor(
StatusBarConnectedDisplays.assertInNewMode()
OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon(this.key)
}
- val colors =
- ColorsModel.Custom(
- backgroundColorInt = this.promotedContent.colors.backgroundColor,
- primaryTextColorInt = this.promotedContent.colors.primaryTextColor,
- )
+ val colors = this.promotedContent.toCustomColorsModel()
val onClickListener =
View.OnClickListener {
// The notification pipeline needs everything to run on the main thread, so keep
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt
index cac25d04f1a5..25f90f9a0065 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt
@@ -21,6 +21,7 @@ import android.content.res.ColorStateList
import androidx.annotation.ColorInt
import com.android.settingslib.Utils
import com.android.systemui.res.R
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
/** Model representing how the chip in the status bar should be colored. */
sealed interface ColorsModel {
@@ -55,4 +56,14 @@ sealed interface ColorsModel {
override fun text(context: Context) = context.getColor(android.R.color.white)
}
+
+ companion object {
+ /** Converts the promoted notification colors to a [Custom] colors model. */
+ fun PromotedNotificationContentModel.toCustomColorsModel(): Custom {
+ return Custom(
+ backgroundColorInt = this.colors.backgroundColor,
+ primaryTextColorInt = this.colors.primaryTextColor,
+ )
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarConntectedDisplays.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarConnectedDisplays.kt
index 54a18f764406..06474b01287d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarConntectedDisplays.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarConnectedDisplays.kt
@@ -16,9 +16,9 @@
package com.android.systemui.statusbar.core
-import com.android.systemui.Flags
import com.android.systemui.flags.FlagToken
import com.android.systemui.flags.RefactorFlagUtils
+import com.android.systemui.shared.Flags
/** Helper for reading or using the status bar connected displays flag state. */
@Suppress("NOTHING_TO_INLINE")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarRootModernization.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarRootModernization.kt
index 057213fa4b18..3c30f3cbec85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarRootModernization.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarRootModernization.kt
@@ -25,6 +25,9 @@ object StatusBarRootModernization {
/** Aconfig flag for removing the fragment */
const val FLAG_NAME = Flags.FLAG_STATUS_BAR_ROOT_MODERNIZATION
+ /** Shows a "compose->bar" text in the status bar for debug purposes */
+ const val SHOW_DISAMBIGUATION = false
+
/** A token used for dependency declaration */
val token: FlagToken
get() = FlagToken(FLAG_NAME, isEnabled)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/headsup/shared/StatusBarNoHunBehavior.kt b/packages/SystemUI/src/com/android/systemui/statusbar/headsup/shared/StatusBarNoHunBehavior.kt
new file mode 100644
index 000000000000..2ae54d7c6c83
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/headsup/shared/StatusBarNoHunBehavior.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.headsup.shared
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for reading or using the status bar no hun behavior flag state. */
+@Suppress("NOTHING_TO_INLINE")
+object StatusBarNoHunBehavior {
+ /** The aconfig flag name */
+ const val FLAG_NAME = Flags.FLAG_STATUS_BAR_NO_HUN_BEHAVIOR
+
+ /** A token used for dependency declaration */
+ val token: FlagToken
+ get() = FlagToken(FLAG_NAME, isEnabled)
+
+ /** Is the refactor enabled */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.statusBarNoHunBehavior() && android.app.Flags.notificationsRedesignAppIcons()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This will throw an exception if
+ * the flag is not enabled to ensure that the refactor author catches issues in testing.
+ * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
+ */
+ @JvmStatic
+ inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
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 c38b84b710bc..417e57d2205f 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
@@ -34,6 +34,8 @@ import static com.android.systemui.statusbar.notification.stack.NotificationPrio
import static java.util.Objects.requireNonNull;
+import android.annotation.FlaggedApi;
+import android.app.Flags;
import android.app.Notification;
import android.app.Notification.MessagingStyle.Message;
import android.app.NotificationChannel;
@@ -1091,6 +1093,14 @@ public final class NotificationEntry extends ListEntry {
}
/**
+ * Returns whether the NotificationEntry is promoted ongoing.
+ */
+ @FlaggedApi(Flags.FLAG_API_RICH_ONGOING)
+ public boolean isPromotedOngoing() {
+ return PromotedNotificationContentModel.isPromotedForStatusBarChip(mSbn.getNotification());
+ }
+
+ /**
* Sets the content needed to render this notification as a promoted notification on various
* surfaces (like status bar chips and AOD).
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt
new file mode 100644
index 000000000000..629cb831f17a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for reading or using the every change not allowed in heads up Group mode flag state. */
+@Suppress("NOTHING_TO_INLINE")
+object StabilizeHeadsUpGroup {
+ /** The aconfig flag name */
+ const val FLAG_NAME: String = Flags.FLAG_STABILIZE_HEADS_UP_GROUP
+
+ /** A token used for dependency declaration */
+ val token: FlagToken
+ get() = FlagToken(FLAG_NAME, isEnabled)
+
+ /** Is the refactor enabled */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.stabilizeHeadsUpGroup()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This will throw an exception if
+ * the flag is not enabled to ensure that the refactor author catches issues in testing.
+ * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
+ */
+ @JvmStatic
+ inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
index 3c31d893cf72..49d5029bbc70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
@@ -26,6 +26,7 @@ import com.android.systemui.Flags;
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;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
@@ -41,11 +42,12 @@ import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor;
-import com.android.systemui.statusbar.notification.shared.NotificationMinimalism;
import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
+import com.android.systemui.statusbar.notification.shared.NotificationMinimalism;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.kotlin.BooleanFlowOperators;
@@ -54,6 +56,7 @@ import com.android.systemui.util.kotlin.JavaAdapter;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -68,6 +71,7 @@ import javax.inject.Inject;
@SysUISingleton
public class VisualStabilityCoordinator implements Coordinator, Dumpable {
private final DelayableExecutor mDelayableExecutor;
+ private final DelayableExecutor mMainExecutor;
private final HeadsUpManager mHeadsUpManager;
private final SeenNotificationsInteractor mSeenNotificationsInteractor;
private final ShadeAnimationInteractor mShadeAnimationInteractor;
@@ -91,6 +95,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {
private boolean mCommunalShowing = false;
private boolean mLockscreenShowing = false;
private boolean mLockscreenInGoneTransition = false;
+ private Set<String> mHeadsUpGroupKeys = new HashSet<>();
private boolean mPipelineRunAllowed;
private boolean mReorderingAllowed;
@@ -110,6 +115,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {
@Inject
public VisualStabilityCoordinator(
@Background DelayableExecutor delayableExecutor,
+ @Main DelayableExecutor mainExecutor,
DumpManager dumpManager,
HeadsUpManager headsUpManager,
ShadeAnimationInteractor shadeAnimationInteractor,
@@ -133,6 +139,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {
mWakefulnessLifecycle = wakefulnessLifecycle;
mStatusBarStateController = statusBarStateController;
mDelayableExecutor = delayableExecutor;
+ mMainExecutor = mainExecutor;
mCommunalSceneInteractor = communalSceneInteractor;
mShadeInteractor = shadeInteractor;
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
@@ -161,6 +168,11 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {
),
this::onCommunalShowingChanged);
+
+ if (StabilizeHeadsUpGroup.isEnabled()) {
+ pipeline.addOnBeforeRenderListListener(mOnBeforeRenderListListener);
+ }
+
if (SceneContainerFlag.isEnabled()) {
mJavaAdapter.alwaysCollectFlow(mKeyguardTransitionInteractor.transitionValue(
KeyguardState.LOCKSCREEN),
@@ -176,10 +188,37 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {
mKeyguardStateController.addCallback(mKeyguardFadeAwayAnimationCallback);
}
}
-
pipeline.setVisualStabilityManager(mNotifStabilityManager);
}
+ /**
+ * Setter of heads up group keys.
+ */
+ @VisibleForTesting
+ public void setHeadsUpGroupKeys(Set<String> currentHeadsUpGroupKeys) {
+ if (StabilizeHeadsUpGroup.isUnexpectedlyInLegacyMode()) {
+ return;
+ }
+
+ if (currentHeadsUpGroupKeys == null) {
+ currentHeadsUpGroupKeys = new HashSet<>();
+ }
+
+ boolean isAnyHeadsUpGroupRemoved = false;
+ for (String headsUpKey: mHeadsUpGroupKeys) {
+ if (!currentHeadsUpGroupKeys.contains(headsUpKey)) {
+ isAnyHeadsUpGroupRemoved = true;
+ break;
+ }
+ }
+ mHeadsUpGroupKeys = currentHeadsUpGroupKeys;
+
+ if (isAnyHeadsUpGroupRemoved) {
+ updateAllowedStates("headsUpGroupEntryChange",
+ mHeadsUpGroupKeys.isEmpty(), /* async= */ true);
+ }
+ }
+
final KeyguardStateController.Callback mKeyguardFadeAwayAnimationCallback =
new KeyguardStateController.Callback() {
@Override
@@ -206,6 +245,64 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {
return false;
}
+ private boolean isParentHeadsUpGroup(NotificationEntry entry) {
+ if (StabilizeHeadsUpGroup.isUnexpectedlyInLegacyMode()) {
+ return false;
+ }
+ if (entry == null) {
+ return false;
+ }
+
+ final GroupEntry parent = entry.getParent();
+
+ if (parent == null) {
+ return false;
+ }
+
+ return isHeadsUpGroup(parent);
+ }
+
+ private boolean isHeadsUpGroup(GroupEntry groupEntry) {
+ if (StabilizeHeadsUpGroup.isUnexpectedlyInLegacyMode()) {
+ return false;
+ }
+
+ if (groupEntry == null) {
+ return false;
+ }
+
+ final NotificationEntry summary = groupEntry.getSummary();
+ if (summary == null) {
+ return false;
+ }
+
+ return mHeadsUpManager.isHeadsUpEntry(summary.getKey());
+ }
+ /**
+ * When reordering is enabled, non-heads-up groups can be pruned.
+ * @return true if the given group entry can be pruned.
+ */
+ private boolean canReorderGroupEntry(GroupEntry entry) {
+ if (StabilizeHeadsUpGroup.isUnexpectedlyInLegacyMode()) {
+ return false;
+ }
+
+ return entry != null && mReorderingAllowed && !isHeadsUpGroup(entry);
+ }
+
+ /**
+ * When reordering is enabled, notifications in non-heads-up groups notifications
+ * are allowed to change.
+ * @return true if the given notification entry can changed.
+ */
+ private boolean canReorderNotificationEntry(NotificationEntry entry) {
+ if (StabilizeHeadsUpGroup.isUnexpectedlyInLegacyMode()) {
+ return false;
+ }
+
+ return entry != null && mReorderingAllowed && !isParentHeadsUpGroup(entry);
+ }
+
@Override
public void onBeginRun() {
mIsSuppressingPipelineRun = false;
@@ -222,25 +319,50 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {
@Override
public boolean isGroupChangeAllowed(@NonNull NotificationEntry entry) {
- final boolean isGroupChangeAllowedForEntry =
- mReorderingAllowed || canMoveForHeadsUp(entry);
+ final boolean isGroupChangeAllowedForEntry;
+ if (StabilizeHeadsUpGroup.isEnabled()) {
+ isGroupChangeAllowedForEntry =
+ isEveryChangeAllowed()
+ || canReorderNotificationEntry(entry)
+ || canMoveForHeadsUp(entry);
+ } else {
+ isGroupChangeAllowedForEntry = mReorderingAllowed
+ || canMoveForHeadsUp(entry);
+ }
mIsSuppressingGroupChange |= !isGroupChangeAllowedForEntry;
return isGroupChangeAllowedForEntry;
}
@Override
public boolean isGroupPruneAllowed(@NonNull GroupEntry entry) {
- final boolean isGroupPruneAllowedForEntry = mReorderingAllowed;
+ boolean isGroupPruneAllowedForEntry;
+ if (StabilizeHeadsUpGroup.isEnabled()) {
+ isGroupPruneAllowedForEntry = isEveryChangeAllowed()
+ || canReorderGroupEntry(entry);
+ } else {
+ isGroupPruneAllowedForEntry = mReorderingAllowed;
+ }
+
mIsSuppressingGroupChange |= !isGroupPruneAllowedForEntry;
return isGroupPruneAllowedForEntry;
}
@Override
public boolean isSectionChangeAllowed(@NonNull NotificationEntry entry) {
- final boolean isSectionChangeAllowedForEntry =
- mReorderingAllowed
- || canMoveForHeadsUp(entry)
- || mEntriesThatCanChangeSection.containsKey(entry.getKey());
+ final boolean isSectionChangeAllowedForEntry;
+ if (StabilizeHeadsUpGroup.isEnabled()) {
+ isSectionChangeAllowedForEntry =
+ isEveryChangeAllowed()
+ || canReorderNotificationEntry(entry)
+ || canMoveForHeadsUp(entry)
+ || mEntriesThatCanChangeSection.containsKey(entry.getKey());
+ } else {
+ isSectionChangeAllowedForEntry =
+ mReorderingAllowed
+ || canMoveForHeadsUp(entry)
+ || mEntriesThatCanChangeSection.containsKey(entry.getKey());
+ }
+
if (!isSectionChangeAllowedForEntry) {
mEntriesWithSuppressedSectionChange.add(entry.getKey());
}
@@ -249,12 +371,27 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {
@Override
public boolean isEntryReorderingAllowed(@NonNull ListEntry entry) {
- return mReorderingAllowed || canMoveForHeadsUp(entry.getRepresentativeEntry());
+ if (StabilizeHeadsUpGroup.isEnabled()) {
+ if (isEveryChangeAllowed()) {
+ return true;
+ }
+
+ final NotificationEntry notificationEntry = entry.getRepresentativeEntry();
+ return canReorderNotificationEntry(notificationEntry)
+ || canMoveForHeadsUp(notificationEntry);
+ } else {
+ return mReorderingAllowed || canMoveForHeadsUp(
+ entry.getRepresentativeEntry());
+ }
}
@Override
public boolean isEveryChangeAllowed() {
- return mReorderingAllowed;
+ if (StabilizeHeadsUpGroup.isEnabled()) {
+ return mReorderingAllowed && mHeadsUpGroupKeys.isEmpty();
+ } else {
+ return mReorderingAllowed;
+ }
}
@Override
@@ -263,7 +400,37 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {
}
};
+ private final OnBeforeRenderListListener mOnBeforeRenderListListener =
+ new OnBeforeRenderListListener() {
+ @Override
+ public void onBeforeRenderList(List<ListEntry> entries) {
+ if (StabilizeHeadsUpGroup.isUnexpectedlyInLegacyMode()) {
+ return;
+ }
+
+ final Set<String> currentHeadsUpKeys = new HashSet<>();
+
+ for (int i = 0; i < entries.size(); i++) {
+ if (entries.get(i) instanceof GroupEntry groupEntry) {
+ final NotificationEntry summary = groupEntry.getSummary();
+ if (summary == null) continue;
+
+ final String summaryKey = summary.getKey();
+ if (mHeadsUpManager.isHeadsUpEntry(summaryKey)) {
+ currentHeadsUpKeys.add(summaryKey);
+ }
+ }
+ }
+
+ setHeadsUpGroupKeys(currentHeadsUpKeys);
+ }
+ };
+
private void updateAllowedStates(String field, boolean value) {
+ updateAllowedStates(field, value, /* async = */ false);
+ }
+
+ private void updateAllowedStates(String field, boolean value, boolean async) {
boolean wasPipelineRunAllowed = mPipelineRunAllowed;
boolean wasReorderingAllowed = mReorderingAllowed;
// No need to run notification pipeline when the lockscreen is in fading animation.
@@ -275,20 +442,28 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {
mLogger.logAllowancesChanged(
wasPipelineRunAllowed, mPipelineRunAllowed,
wasReorderingAllowed, mReorderingAllowed,
- field, value);
+ field, value, async);
}
+ if (async) {
+ mMainExecutor.execute(this::maybeInvalidateList);
+ } else {
+ maybeInvalidateList();
+ }
+ mVisualStabilityProvider.setReorderingAllowed(mReorderingAllowed);
+ }
+
+ private void maybeInvalidateList() {
if (mPipelineRunAllowed && mIsSuppressingPipelineRun) {
mNotifStabilityManager.invalidateList("pipeline run suppression ended");
} else if (mReorderingAllowed && (mIsSuppressingGroupChange
|| isSuppressingSectionChange()
|| mIsSuppressingEntryReorder)) {
- String reason = "reorder suppression ended for"
+ final String reason = "reorder suppression ended for"
+ " group=" + mIsSuppressingGroupChange
+ " section=" + isSuppressingSectionChange()
+ " sort=" + mIsSuppressingEntryReorder;
mNotifStabilityManager.invalidateList(reason);
}
- mVisualStabilityProvider.setReorderingAllowed(mReorderingAllowed);
}
private boolean isSuppressingSectionChange() {
@@ -393,6 +568,9 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {
pw.println("isSuppressingPipelineRun: " + mIsSuppressingPipelineRun);
pw.println("isSuppressingGroupChange: " + mIsSuppressingGroupChange);
pw.println("isSuppressingEntryReorder: " + mIsSuppressingEntryReorder);
+ if (StabilizeHeadsUpGroup.isEnabled()) {
+ pw.println("headsUpGroupKeys: " + mHeadsUpGroupKeys.size());
+ }
pw.println("entriesWithSuppressedSectionChange: "
+ mEntriesWithSuppressedSectionChange.size());
for (String key : mEntriesWithSuppressedSectionChange) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorLogger.kt
index fe23e4e12db4..5051afc53881 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorLogger.kt
@@ -32,7 +32,8 @@ constructor(@VisualStabilityLog private val buffer: LogBuffer) {
wasReorderingAllowed: Boolean,
isReorderingAllowed: Boolean,
field: String,
- value: Boolean
+ value: Boolean,
+ async: Boolean,
) {
buffer.log(
TAG,
@@ -44,13 +45,15 @@ constructor(@VisualStabilityLog private val buffer: LogBuffer) {
bool4 = isReorderingAllowed
str1 = field
str2 = value.toString()
+ str3 = async.toString()
},
{
"stability allowances changed:" +
" pipelineRunAllowed $bool1->$bool2" +
" reorderingAllowed $bool3->$bool4" +
" when setting $str1=$str2"
- }
+ " async=$str3"
+ },
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index d83acf34ca99..9ed1632c8bc6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -248,8 +248,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
@NonNull NotifInflater.Params inflaterParams,
ExpandableNotificationRow row,
@Nullable NotificationRowContentBinder.InflationCallback inflationCallback) {
- final boolean useIncreasedCollapsedHeight =
- mMessagingUtil.isImportantMessaging(entry.getSbn(), entry.getImportance());
final boolean isMinimized = inflaterParams.isMinimized();
// Set show snooze action
@@ -258,7 +256,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
RowContentBindParams params = mRowContentBindStage.getStageParams(entry);
params.requireContentViews(FLAG_CONTENT_VIEW_CONTRACTED);
params.requireContentViews(FLAG_CONTENT_VIEW_EXPANDED);
- params.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
params.setUseMinimized(isMinimized);
int redactionType = inflaterParams.getRedactionType();
@@ -303,7 +300,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
mLogger.logRequestingRebind(entry, inflaterParams);
mRowContentBindStage.requestRebind(entry, en -> {
mLogger.logRebindComplete(entry);
- row.setUsesIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
row.setIsMinimized(isMinimized);
if (inflationCallback != null) {
inflationCallback.onAsyncInflationFinished(en);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index ea48fb4ffd92..086c32cbae5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -60,7 +60,6 @@ import com.android.systemui.statusbar.notification.collection.render.Notificatio
import com.android.systemui.statusbar.notification.data.NotificationDataLayerModule;
import com.android.systemui.statusbar.notification.domain.NotificationDomainLayerModule;
import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor;
-import com.android.systemui.statusbar.notification.footer.ui.viewmodel.FooterViewModelModule;
import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
import com.android.systemui.statusbar.notification.icon.ConversationIconManager;
import com.android.systemui.statusbar.notification.icon.IconManager;
@@ -109,7 +108,6 @@ import javax.inject.Provider;
* Dagger Module for classes found within the com.android.systemui.statusbar.notification package.
*/
@Module(includes = {
- FooterViewModelModule.class,
KeyguardNotificationVisibilityProviderModule.class,
NotificationDataLayerModule.class,
NotificationDomainLayerModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt
index 0c040c855368..502fb51ba5c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt
@@ -76,11 +76,14 @@ constructor(
val allNotificationsCountValue: Int
get() = repository.activeNotifications.value.individuals.size
- /** The notifications that are promoted and ongoing. Sorted by priority order. */
+ /**
+ * The notifications that are promoted and ongoing.
+ *
+ * This *may* include ongoing call notifications if the call notification also meets promotion
+ * criteria.
+ */
val promotedOngoingNotifications: Flow<List<ActiveNotificationModel>> =
if (StatusBarNotifChips.isEnabled) {
- // TODO(b/364653005): [ongoingCallNotification] should be incorporated into this flow
- // instead of being separate.
topLevelRepresentativeNotifications
.map { notifs -> notifs.filter { it.promotedContent != null } }
.distinctUntilChanged()
@@ -98,10 +101,10 @@ constructor(
val ongoingCallNotification: Flow<ActiveNotificationModel?> =
allRepresentativeNotifications
.map { notifMap ->
- // Once a call has started, its `whenTime` should stay the same, so we can use it as
- // a stable sort value.
notifMap.values
- .filter { it.callType == CallType.Ongoing }
+ .filter { it.isOngoingCallNotification() }
+ // Once a call has started, its `whenTime` should stay the same, so we can use
+ // it as a stable sort value.
.minByOrNull { it.whenTime }
}
.distinctUntilChanged()
@@ -153,4 +156,8 @@ constructor(
fun setNotifStats(notifStats: NotifStats) {
repository.notifStats.value = notifStats
}
+
+ companion object {
+ fun ActiveNotificationModel.isOngoingCallNotification() = this.callType == CallType.Ongoing
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationIconInteractor.kt
index 17b6e9f572c9..e5cc3b973c51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationIconInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationIconInteractor.kt
@@ -16,16 +16,19 @@
package com.android.systemui.statusbar.notification.domain.interactor
import android.graphics.Rect
+import com.android.systemui.statusbar.headsup.shared.StatusBarNoHunBehavior
import com.android.systemui.statusbar.notification.data.repository.HeadsUpNotificationIconViewStateRepository
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
-/** Domain logic pertaining to heads up notification icons. */
+/**
+ * Domain logic pertaining to heads up notification icons.
+ *
+ * If [StatusBarNoHunBehavior] is enabled, this class should do nothing.
+ */
class HeadsUpNotificationIconInteractor
@Inject
-constructor(
- private val repository: HeadsUpNotificationIconViewStateRepository,
-) {
+constructor(private val repository: HeadsUpNotificationIconViewStateRepository) {
/** Notification key for a notification icon to show isolated, or `null` if none. */
val isolatedIconLocation: Flow<Rect?> = repository.isolatedIconLocation
@@ -34,11 +37,13 @@ constructor(
/** Updates the location where isolated notification icons are shown. */
fun setIsolatedIconLocation(rect: Rect?) {
+ StatusBarNoHunBehavior.assertInLegacyMode()
repository.isolatedIconLocation.value = rect
}
/** Updates which notification will have its icon displayed isolated. */
fun setIsolatedIconNotificationKey(key: String?) {
+ StatusBarNoHunBehavior.assertInLegacyMode()
repository.isolatedNotification.value = key
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
index a670f69df601..c88dd7af6b24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
@@ -40,6 +40,7 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import com.android.systemui.res.R;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.statusbar.notification.ColorUpdateLogger;
import com.android.systemui.statusbar.notification.footer.shared.NotifRedesignFooter;
import com.android.systemui.statusbar.notification.row.FooterViewButton;
@@ -333,11 +334,9 @@ public class FooterView extends StackScrollerDecorView {
/**
* Whether the touch is outside the Clear all button.
- *
- * TODO(b/293167744): This is an artifact from the time when we could press underneath the
- * shade to dismiss it. Check if it's safe to remove.
*/
public boolean isOnEmptySpace(float touchX, float touchY) {
+ SceneContainerFlag.assertInLegacyMode();
return touchX < mContent.getX()
|| touchX > mContent.getX() + mContent.getWidth()
|| touchY < mContent.getY()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt
index 5696e9f0c5a2..c895c41960d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification.footer.ui.viewmodel
import android.content.Intent
import android.provider.Settings
import com.android.internal.jank.InteractionJankMonitor
-import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.res.R
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shared.notifications.domain.interactor.NotificationSettingsInteractor
@@ -32,10 +31,8 @@ import com.android.systemui.util.kotlin.sample
import com.android.systemui.util.ui.AnimatableEvent
import com.android.systemui.util.ui.AnimatedValue
import com.android.systemui.util.ui.toAnimatedValueFlow
-import dagger.Module
-import dagger.Provides
-import java.util.Optional
-import javax.inject.Provider
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -44,7 +41,9 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
/** ViewModel for [FooterView]. */
-class FooterViewModel(
+class FooterViewModel
+@AssistedInject
+constructor(
activeNotificationsInteractor: ActiveNotificationsInteractor,
notificationSettingsInteractor: NotificationSettingsInteractor,
seenNotificationsInteractor: SeenNotificationsInteractor,
@@ -141,25 +140,9 @@ class FooterViewModel(
AnimatedValue.NotAnimating(!messageVisible)
},
)
-}
-// TODO: b/293167744 - remove this, use new viewmodel style
-@Module
-object FooterViewModelModule {
- @Provides
- @SysUISingleton
- fun provideOptional(
- activeNotificationsInteractor: Provider<ActiveNotificationsInteractor>,
- notificationSettingsInteractor: Provider<NotificationSettingsInteractor>,
- seenNotificationsInteractor: Provider<SeenNotificationsInteractor>,
- shadeInteractor: Provider<ShadeInteractor>,
- ): Optional<FooterViewModel> =
- Optional.of(
- FooterViewModel(
- activeNotificationsInteractor.get(),
- notificationSettingsInteractor.get(),
- seenNotificationsInteractor.get(),
- shadeInteractor.get(),
- )
- )
+ @AssistedFactory
+ interface Factory {
+ fun create(): FooterViewModel
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
index d02e17cab534..0171fb72e158 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
@@ -1425,7 +1425,12 @@ public class HeadsUpManagerImpl
}
}
- return (mEntry.isRowPinned() && mExpanded)
+ // Promoted notifications are always shown as expanded, and we don't want them to ever
+ // be sticky.
+ boolean isStickyDueToExpansion =
+ mEntry.isRowPinned() && mExpanded && !mEntry.isPromotedOngoing();
+
+ return isStickyDueToExpansion
|| mRemoteInputActive
|| hasFullScreenIntent(mEntry);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
index 643ee249e75e..348552f81fa7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
@@ -32,6 +32,7 @@ import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.headsup.shared.StatusBarNoHunBehavior
import com.android.systemui.statusbar.notification.collection.NotifCollection
import com.android.systemui.statusbar.notification.icon.IconPack
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder.IconViewStore
@@ -81,7 +82,9 @@ object NotificationIconContainerViewBinder {
StatusBarIconViewBinder.bindIconColors(sbiv, iconColors, contrastColorUtil)
}
}
- launch { viewModel.bindIsolatedIcon(view, viewStore) }
+ if (!StatusBarNoHunBehavior.isEnabled) {
+ launch { viewModel.bindIsolatedIcon(view, viewStore) }
+ }
launch { viewModel.animationsEnabled.bindAnimationsEnabled(view) }
}
@@ -146,6 +149,7 @@ object NotificationIconContainerViewBinder {
view: NotificationIconContainer,
viewStore: IconViewStore,
) {
+ StatusBarNoHunBehavior.assertInLegacyMode()
coroutineScope {
launch {
isolatedIconLocation.collectTracingEach("NIC#isolatedIconLocation") { location ->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
index e1032820fb71..8f43c323aeb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
@@ -23,6 +23,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.plugins.DarkIconDispatcher
import com.android.systemui.res.R
import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.statusbar.headsup.shared.StatusBarNoHunBehavior
import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor
import com.android.systemui.statusbar.notification.icon.domain.interactor.StatusBarNotificationIconsInteractor
import com.android.systemui.statusbar.phone.domain.interactor.DarkIconInteractor
@@ -37,7 +38,9 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
@@ -92,31 +95,42 @@ constructor(
/** An Icon to show "isolated" in the IconContainer. */
val isolatedIcon: Flow<AnimatedValue<NotificationIconInfo?>> =
- headsUpIconInteractor.isolatedNotification
- .combine(icons) { isolatedNotif, iconsViewData ->
- isolatedNotif?.let {
- iconsViewData.visibleIcons.firstOrNull { it.notifKey == isolatedNotif }
- }
- }
- .distinctUntilChanged()
- .flowOn(bgContext)
- .conflate()
- .distinctUntilChanged()
- .pairwise(initialValue = null)
- .sample(shadeInteractor.shadeExpansion) { (prev, iconInfo), shadeExpansion ->
- val animate =
- when {
- iconInfo?.notifKey == prev?.notifKey -> false
- iconInfo == null || prev == null -> shadeExpansion == 0f
- else -> false
+ if (StatusBarNoHunBehavior.isEnabled) {
+ flowOf(AnimatedValue.NotAnimating(null))
+ } else {
+ headsUpIconInteractor.isolatedNotification
+ .combine(icons) { isolatedNotif, iconsViewData ->
+ isolatedNotif?.let {
+ iconsViewData.visibleIcons.firstOrNull { it.notifKey == isolatedNotif }
}
- AnimatableEvent(iconInfo, animate)
- }
- .toAnimatedValueFlow()
+ }
+ .distinctUntilChanged()
+ .flowOn(bgContext)
+ .conflate()
+ .distinctUntilChanged()
+ .pairwise(initialValue = null)
+ .sample(shadeInteractor.shadeExpansion) { (prev, iconInfo), shadeExpansion ->
+ val animate =
+ when {
+ iconInfo?.notifKey == prev?.notifKey -> false
+ iconInfo == null || prev == null -> shadeExpansion == 0f
+ else -> false
+ }
+ AnimatableEvent(iconInfo, animate)
+ }
+ .toAnimatedValueFlow()
+ }
/** Location to show an isolated icon, if there is one. */
val isolatedIconLocation: Flow<Rect> =
- headsUpIconInteractor.isolatedIconLocation.filterNotNull().conflate().distinctUntilChanged()
+ if (StatusBarNoHunBehavior.isEnabled) {
+ emptyFlow()
+ } else {
+ headsUpIconInteractor.isolatedIconLocation
+ .filterNotNull()
+ .conflate()
+ .distinctUntilChanged()
+ }
private class IconColorsImpl(override val tint: Int, private val areas: Collection<Rect>) :
NotificationIconColors {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index 0a9899e88d24..c3266fc57c2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -93,7 +93,6 @@ constructor(
clickerBuilder.build(bubblesOptional, notificationActivityStarter)
)
notificationRowBinder.setUpWithPresenter(presenter, listContainer)
- headsUpViewBinder.setPresenter(presenter)
notifBindPipelineInitializer.initialize()
animatedImageNotificationManager.bind()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java
index 32ec02319241..9988f729a11a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java
@@ -23,9 +23,7 @@ import android.util.ArrayMap;
import androidx.annotation.Nullable;
import androidx.core.os.CancellationSignal;
-import com.android.internal.util.NotificationMessagingUtil;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator;
import com.android.systemui.statusbar.notification.row.RowContentBindParams;
@@ -45,30 +43,18 @@ import javax.inject.Inject;
@SysUISingleton
public class HeadsUpViewBinder {
private final RowContentBindStage mStage;
- private final NotificationMessagingUtil mNotificationMessagingUtil;
private final Map<NotificationEntry, CancellationSignal> mOngoingBindCallbacks =
new ArrayMap<>();
private final HeadsUpViewBinderLogger mLogger;
- private NotificationPresenter mNotificationPresenter;
@Inject
- HeadsUpViewBinder(
- NotificationMessagingUtil notificationMessagingUtil,
- RowContentBindStage bindStage, HeadsUpViewBinderLogger logger) {
- mNotificationMessagingUtil = notificationMessagingUtil;
+ HeadsUpViewBinder(RowContentBindStage bindStage, HeadsUpViewBinderLogger logger) {
mStage = bindStage;
mLogger = logger;
}
/**
- * Set notification presenter to determine parameters for heads up view inflation.
- */
- public void setPresenter(NotificationPresenter presenter) {
- mNotificationPresenter = presenter;
- }
-
- /**
* Bind heads up view to the notification row.
* @param callback callback after heads up view is bound
*/
@@ -77,15 +63,9 @@ public class HeadsUpViewBinder {
boolean isPinnedByUser,
@Nullable HeadsUpBindCallback callback) {
RowContentBindParams params = mStage.getStageParams(entry);
- final boolean isImportantMessage = mNotificationMessagingUtil.isImportantMessaging(
- entry.getSbn(), entry.getImportance());
- final boolean useIncreasedHeadsUp = isImportantMessage
- && !mNotificationPresenter.isPresenterFullyCollapsed();
- params.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp);
params.requireContentViews(FLAG_CONTENT_VIEW_HEADS_UP);
CancellationSignal signal = mStage.requestRebind(entry, en -> {
mLogger.entryBoundSuccessfully(entry);
- en.getRow().setUsesIncreasedHeadsUpHeight(params.useIncreasedHeadsUpHeight());
// requestRebind promises that if we called cancel before this callback would be
// invoked, then we will not enter this callback, and because we always cancel before
// adding to this map, we know this will remove the correct signal.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt
index 258d80c60cd7..a175f90c384a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt
@@ -147,6 +147,7 @@ data class PromotedNotificationContentModel(
* Returns true if the given notification should be considered promoted when deciding
* whether or not to show the status bar chip UI.
*/
+ @JvmStatic
fun isPromotedForStatusBarChip(notification: Notification): Boolean {
// Notification.isPromotedOngoing checks the ui_rich_ongoing flag, but we want the
// status bar chip to be ready before all the features behind the ui_rich_ongoing flag
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 95604c113a15..598ff09ba3b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -191,12 +191,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private int mMaxHeadsUpHeightBeforeP;
private int mMaxHeadsUpHeightBeforeS;
private int mMaxHeadsUpHeight;
- private int mMaxHeadsUpHeightIncreased;
private int mMaxSmallHeightBeforeN;
private int mMaxSmallHeightBeforeP;
private int mMaxSmallHeightBeforeS;
private int mMaxSmallHeight;
- private int mMaxSmallHeightLarge;
private int mMaxExpandedHeight;
private int mNotificationLaunchHeight;
private boolean mMustStayOnScreen;
@@ -414,8 +412,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private OnUserInteractionCallback mOnUserInteractionCallback;
private NotificationGutsManager mNotificationGutsManager;
private boolean mIsMinimized;
- private boolean mUseIncreasedCollapsedHeight;
- private boolean mUseIncreasedHeadsUpHeight;
private float mTranslationWhenRemoved;
private boolean mWasChildInGroupWhenRemoved;
private final NotificationInlineImageResolver mImageResolver;
@@ -828,8 +824,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
} else if (isCallLayout) {
smallHeight = mMaxExpandedHeight;
- } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
- smallHeight = mMaxSmallHeightLarge;
} else {
smallHeight = mMaxSmallHeight;
}
@@ -845,8 +839,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
} else {
headsUpHeight = mMaxHeadsUpHeightBeforeS;
}
- } else if (mUseIncreasedHeadsUpHeight && layout == mPrivateLayout) {
- headsUpHeight = mMaxHeadsUpHeightIncreased;
} else {
headsUpHeight = mMaxHeadsUpHeight;
}
@@ -1848,14 +1840,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return mIsMinimized;
}
- public void setUsesIncreasedCollapsedHeight(boolean use) {
- mUseIncreasedCollapsedHeight = use;
- }
-
- public void setUsesIncreasedHeadsUpHeight(boolean use) {
- mUseIncreasedHeadsUpHeight = use;
- }
-
/**
* Interface for logging {{@link ExpandableNotificationRow} events.}
*/
@@ -2086,8 +2070,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mMaxSmallHeight = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.notification_min_height);
}
- mMaxSmallHeightLarge = NotificationUtils.getFontScaledHeight(mContext,
- R.dimen.notification_min_height_increased);
mMaxExpandedHeight = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.notification_max_height);
mMaxHeadsUpHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext,
@@ -2098,8 +2080,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
R.dimen.notification_max_heads_up_height_before_s);
mMaxHeadsUpHeight = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.notification_max_heads_up_height);
- mMaxHeadsUpHeightIncreased = NotificationUtils.getFontScaledHeight(mContext,
- R.dimen.notification_max_heads_up_height_increased);
Resources res = getResources();
mEnableNonGroupedNotificationExpand =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt
index e27ff7d6746b..793b3b8b1e42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt
@@ -17,39 +17,210 @@
package com.android.systemui.statusbar.notification.row
import android.content.Context
+import android.graphics.BlendMode
import android.graphics.Canvas
+import android.graphics.Color
import android.graphics.ColorFilter
+import android.graphics.LinearGradient
import android.graphics.Paint
+import android.graphics.Path
import android.graphics.PixelFormat
+import android.graphics.Rect
+import android.graphics.RuntimeShader
+import android.graphics.Shader
import android.graphics.drawable.Drawable
+import android.widget.FrameLayout
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.viewinterop.AndroidView
+import com.android.internal.graphics.ColorUtils
+import com.android.systemui.res.R
+import com.android.systemui.surfaceeffects.shaderutil.ShaderUtilLibrary
+import kotlin.math.max
+import kotlin.math.roundToInt
/**
- * A background style for smarter-smart-actions.
- *
- * TODO(b/383567383) implement final UX
+ * A background style for smarter-smart-actions. The style is composed by a simplex3d noise,
+ * overlaid with sparkles.
*/
-class MagicActionBackgroundDrawable(context: Context) : Drawable() {
+class MagicActionBackgroundDrawable(
+ context: Context,
+ primaryContainer: Int? = null,
+ private val seed: Float = 0f,
+) : Drawable() {
+
+ private val pixelDensity = context.resources.displayMetrics.density
+ private val cornerRadius =
+ context.resources.getDimensionPixelSize(R.dimen.smart_reply_button_corner_radius).toFloat()
+ private val outlineStrokeWidth =
+ context.resources
+ .getDimensionPixelSize(R.dimen.smart_action_button_outline_stroke_width)
+ .toFloat()
+ private val buttonShape = Path()
+ private val paddingVertical =
+ context.resources
+ .getDimensionPixelSize(R.dimen.smart_reply_button_padding_vertical)
+ .toFloat()
+
+ /** The color of the button background. */
+ private val mainColor =
+ primaryContainer
+ ?: context.getColor(com.android.internal.R.color.materialColorPrimaryContainer)
- private var _alpha: Int = 255
- private var _colorFilter: ColorFilter? = null
- private val paint =
- Paint().apply {
- color = context.getColor(com.android.internal.R.color.materialColorPrimaryContainer)
+ /** Slightly dimmed down version of [mainColor] used on the simplex noise. */
+ private val dimColor: Int
+ get() {
+ val labColor = arrayOf(0.0, 0.0, 0.0).toDoubleArray()
+ ColorUtils.colorToLAB(mainColor, labColor)
+ val camColor = ColorUtils.colorToCAM(mainColor)
+ return ColorUtils.CAMToColor(
+ camColor.hue,
+ camColor.chroma,
+ max(0f, (labColor[0] - 20).toFloat()),
+ )
}
+ private val bgShader = MagicActionBackgroundShader()
+ private val bgPaint = Paint()
+ private val outlinePaint = Paint()
+
+ init {
+ bgShader.setColorUniform("in_color", mainColor)
+ bgShader.setColorUniform("in_dimColor", dimColor)
+ bgPaint.shader = bgShader
+ outlinePaint.style = Paint.Style.STROKE
+ // Stroke is doubled in width and then clipped, to avoid anti-aliasing artifacts at the edge
+ // of the rectangle.
+ outlinePaint.strokeWidth = outlineStrokeWidth * 2
+ outlinePaint.blendMode = BlendMode.SCREEN
+ outlinePaint.alpha = (255 * 0.32f).roundToInt()
+ }
+
override fun draw(canvas: Canvas) {
- canvas.drawRect(bounds, paint)
+ // We clip instead of drawing 2 rounded rects, otherwise there will be artifacts where
+ // around the button background and the outline.
+ canvas.clipPath(buttonShape)
+
+ canvas.drawRect(bounds, bgPaint)
+ canvas.drawRoundRect(
+ bounds.left.toFloat(),
+ bounds.top + paddingVertical,
+ bounds.right.toFloat(),
+ bounds.bottom - paddingVertical,
+ cornerRadius,
+ cornerRadius,
+ outlinePaint,
+ )
+ }
+
+ override fun onBoundsChange(bounds: Rect) {
+ super.onBoundsChange(bounds)
+
+ val width = bounds.width().toFloat()
+ val height = bounds.height() - paddingVertical * 2
+ if (width == 0f || height == 0f) return
+
+ bgShader.setFloatUniform("in_gridNum", NOISE_SIZE)
+ bgShader.setFloatUniform("in_spkarkleAlpha", SPARKLE_ALPHA)
+ bgShader.setFloatUniform("in_noiseMove", 0f, 0f, 0f)
+ bgShader.setFloatUniform("in_size", width, height)
+ bgShader.setFloatUniform("in_aspectRatio", width / height)
+ bgShader.setFloatUniform("in_time", seed)
+ bgShader.setFloatUniform("in_pixelDensity", pixelDensity)
+
+ buttonShape.reset()
+ buttonShape.addRoundRect(
+ bounds.left.toFloat(),
+ bounds.top + paddingVertical,
+ bounds.right.toFloat(),
+ bounds.bottom - paddingVertical,
+ cornerRadius,
+ cornerRadius,
+ Path.Direction.CW,
+ )
+
+ val outlineGradient =
+ LinearGradient(
+ bounds.left.toFloat(),
+ 0f,
+ bounds.right.toFloat(),
+ 0f,
+ mainColor,
+ ColorUtils.setAlphaComponent(mainColor, 0),
+ Shader.TileMode.CLAMP,
+ )
+ outlinePaint.shader = outlineGradient
}
override fun setAlpha(alpha: Int) {
- _alpha = alpha
+ bgPaint.alpha = alpha
invalidateSelf()
}
override fun setColorFilter(colorFilter: ColorFilter?) {
- _colorFilter = colorFilter
+ bgPaint.colorFilter = colorFilter
invalidateSelf()
}
override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
+
+ companion object {
+ /** Smoothness of the turbulence. Larger numbers yield more detail. */
+ private const val NOISE_SIZE = 0.7f
+
+ /** Strength of the sparkles overlaid on the turbulence. */
+ private const val SPARKLE_ALPHA = 0.15f
+ }
+}
+
+private class MagicActionBackgroundShader : RuntimeShader(SHADER) {
+
+ // language=AGSL
+ companion object {
+ private const val UNIFORMS =
+ """
+ uniform float in_gridNum;
+ uniform vec3 in_noiseMove;
+ uniform vec2 in_size;
+ uniform float in_aspectRatio;
+ uniform half in_time;
+ uniform half in_pixelDensity;
+ uniform float in_spkarkleAlpha;
+ layout(color) uniform vec4 in_color;
+ layout(color) uniform vec4 in_dimColor;
+ """
+ private const val MAIN_SHADER =
+ """vec4 main(vec2 p) {
+ vec2 uv = p / in_size.xy;
+ uv.x *= in_aspectRatio;
+ vec3 noiseP = vec3(uv + in_noiseMove.xy, in_noiseMove.z) * in_gridNum;
+ half luma = 1.0 - getLuminosity(half3(simplex3d(noiseP)));
+ half4 turbulenceColor = mix(in_color, in_dimColor, luma);
+ float sparkle = sparkles(p - mod(p, in_pixelDensity * 0.8), in_time);
+ sparkle = min(sparkle * in_spkarkleAlpha, in_spkarkleAlpha);
+ return turbulenceColor + half4(half3(sparkle), 1.0);
+ }
+ """
+ private const val SHADER = UNIFORMS + ShaderUtilLibrary.SHADER_LIB + MAIN_SHADER
+ }
+}
+
+// @Preview
+@Composable
+fun DrawablePreview() {
+ AndroidView(
+ factory = { context ->
+ FrameLayout(context).apply {
+ background =
+ MagicActionBackgroundDrawable(
+ context = context,
+ primaryContainer = Color.parseColor("#c5eae2"),
+ seed = 0f,
+ )
+ }
+ },
+ modifier = Modifier.size(100.dp, 50.dp),
+ )
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 70e27a981b49..57fe24f40acb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -436,8 +436,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
if ((reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0) {
logger.logAsyncTaskProgress(entryForLogging, "creating contracted remote view");
- result.newContentView = createContentView(builder, bindParams.isMinimized,
- bindParams.usesIncreasedHeight);
+ result.newContentView = createContentView(builder, bindParams.isMinimized);
}
if ((reInflateFlags & FLAG_CONTENT_VIEW_EXPANDED) != 0) {
@@ -451,8 +450,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
if (isHeadsUpCompact) {
result.newHeadsUpView = builder.createCompactHeadsUpContentView();
} else {
- result.newHeadsUpView = builder.createHeadsUpContentView(
- bindParams.usesIncreasedHeadsUpHeight);
+ result.newHeadsUpView = builder.createHeadsUpContentView();
}
}
@@ -462,7 +460,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
&& bindParams.redactionType == REDACTION_TYPE_SENSITIVE_CONTENT) {
result.newPublicView = createSensitiveContentMessageNotification(
row.getEntry().getSbn().getNotification(), builder.getStyle(),
- systemUiContext, packageContext).createContentView(true);
+ systemUiContext, packageContext).createContentView();
} else {
result.newPublicView = builder.makePublicContentView(bindParams.isMinimized);
}
@@ -504,6 +502,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
CharSequence redactedMessage = systemUiContext.getString(
R.string.redacted_notification_single_line_text
);
+ redacted.setWhen(original.getWhen());
if (originalStyle instanceof MessagingStyle oldStyle) {
MessagingStyle newStyle = new MessagingStyle(oldStyle.getUser());
@@ -1134,11 +1133,11 @@ public class NotificationContentInflater implements NotificationRowContentBinder
}
private static RemoteViews createContentView(Notification.Builder builder,
- boolean isMinimized, boolean useLarge) {
+ boolean isMinimized) {
if (isMinimized) {
return builder.makeLowPriorityContentView(false /* useRegularSubtext */);
}
- return builder.createContentView(useLarge);
+ return builder.createContentView();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
index 1cef8791e0ea..0be1d5d9d79d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
@@ -143,11 +143,8 @@ public interface NotificationRowContentBinder {
*/
class BindParams {
- public BindParams(boolean minimized, boolean increasedHeight,
- boolean increasedHeadsUpHeight, int redaction) {
+ public BindParams(boolean minimized, int redaction) {
isMinimized = minimized;
- usesIncreasedHeight = increasedHeight;
- usesIncreasedHeadsUpHeight = increasedHeadsUpHeight;
redactionType = redaction;
}
@@ -157,16 +154,6 @@ public interface NotificationRowContentBinder {
public final boolean isMinimized;
/**
- * Use increased height when binding contracted view.
- */
- public final boolean usesIncreasedHeight;
-
- /**
- * Use increased height when binding heads up views.
- */
- public final boolean usesIncreasedHeadsUpHeight;
-
- /**
* Controls the type of public view to show, if a public view is requested
*/
public final @RedactionType int redactionType;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
index c619b17f1ad8..49e38def98a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
@@ -822,11 +822,7 @@ constructor(
entryForLogging,
"creating contracted remote view",
)
- createContentView(
- builder,
- bindParams.isMinimized,
- bindParams.usesIncreasedHeight,
- )
+ createContentView(builder, bindParams.isMinimized)
} else null
val expanded =
if (reInflateFlags and FLAG_CONTENT_VIEW_EXPANDED != 0) {
@@ -846,7 +842,7 @@ constructor(
if (isHeadsUpCompact) {
builder.createCompactHeadsUpContentView()
} else {
- builder.createHeadsUpContentView(bindParams.usesIncreasedHeadsUpHeight)
+ @Suppress("DEPRECATION") builder.createHeadsUpContentView()
}
} else null
val public =
@@ -862,7 +858,7 @@ constructor(
systemUiContext,
packageContext,
)
- .createContentView(bindParams.usesIncreasedHeight)
+ .createContentView()
} else {
builder.makePublicContentView(bindParams.isMinimized)
}
@@ -1654,11 +1650,12 @@ constructor(
private fun createContentView(
builder: Notification.Builder,
isMinimized: Boolean,
- useLarge: Boolean,
): RemoteViews {
return if (isMinimized) {
builder.makeLowPriorityContentView(false /* useRegularSubtext */)
- } else builder.createContentView(useLarge)
+ } else {
+ @Suppress("DEPRECATION") builder.createContentView()
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
index bc44cb0e1074..adbff10a629b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
@@ -20,7 +20,6 @@ import static com.android.systemui.statusbar.NotificationLockscreenUserManager.R
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.RedactionType;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED;
-import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
@@ -29,8 +28,6 @@ import com.android.systemui.statusbar.notification.row.NotificationRowContentBin
*/
public final class RowContentBindParams {
private boolean mUseMinimized;
- private boolean mUseIncreasedHeight;
- private boolean mUseIncreasedHeadsUpHeight;
private boolean mViewsNeedReinflation;
private @InflationFlag int mContentViews = DEFAULT_INFLATION_FLAGS;
private @RedactionType int mRedactionType = REDACTION_TYPE_NONE;
@@ -75,34 +72,6 @@ public final class RowContentBindParams {
}
/**
- * Set whether content should use an increased height version of its contracted view.
- */
- public void setUseIncreasedCollapsedHeight(boolean useIncreasedHeight) {
- if (mUseIncreasedHeight != useIncreasedHeight) {
- mDirtyContentViews |= FLAG_CONTENT_VIEW_CONTRACTED;
- }
- mUseIncreasedHeight = useIncreasedHeight;
- }
-
- public boolean useIncreasedHeight() {
- return mUseIncreasedHeight;
- }
-
- /**
- * Set whether content should use an increased height version of its heads up view.
- */
- public void setUseIncreasedHeadsUpHeight(boolean useIncreasedHeadsUpHeight) {
- if (mUseIncreasedHeadsUpHeight != useIncreasedHeadsUpHeight) {
- mDirtyContentViews |= FLAG_CONTENT_VIEW_HEADS_UP;
- }
- mUseIncreasedHeadsUpHeight = useIncreasedHeadsUpHeight;
- }
-
- public boolean useIncreasedHeadsUpHeight() {
- return mUseIncreasedHeadsUpHeight;
- }
-
- /**
* Require the specified content views to be bound after the rebind request.
*
* @see InflationFlag
@@ -169,10 +138,8 @@ public final class RowContentBindParams {
@Override
public String toString() {
return String.format("RowContentBindParams[mContentViews=%x mDirtyContentViews=%x "
- + "mUseMinimized=%b mUseIncreasedHeight=%b "
- + "mUseIncreasedHeadsUpHeight=%b mViewsNeedReinflation=%b]",
- mContentViews, mDirtyContentViews, mUseMinimized, mUseIncreasedHeight,
- mUseIncreasedHeadsUpHeight, mViewsNeedReinflation);
+ + "mUseMinimized=%b mViewsNeedReinflation=%b]",
+ mContentViews, mDirtyContentViews, mUseMinimized, mViewsNeedReinflation);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
index 53f74161e7fc..6883ec575d7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
@@ -72,8 +72,7 @@ public class RowContentBindStage extends BindStage<RowContentBindParams> {
// Bind/unbind with parameters
mBinder.unbindContent(entry, row, contentToUnbind);
- BindParams bindParams = new BindParams(params.useMinimized(), params.useIncreasedHeight(),
- params.useIncreasedHeadsUpHeight(), params.getRedactionType());
+ BindParams bindParams = new BindParams(params.useMinimized(), params.getRedactionType());
boolean forceInflate = params.needsReinflation();
InflationCallback inflationCallback = new InflationCallback() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/AppIconProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/AppIconProvider.kt
index 98d704c75d33..52a0f6f92355 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/AppIconProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/AppIconProvider.kt
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification.row.icon
import android.annotation.WorkerThread
import android.app.ActivityManager
import android.app.Flags
+import android.app.Flags.notificationsRedesignThemedAppIcons
import android.content.Context
import android.content.pm.PackageManager.NameNotFoundException
import android.graphics.Color
@@ -29,6 +30,8 @@ import android.util.Log
import com.android.internal.R
import com.android.launcher3.icons.BaseIconFactory
import com.android.launcher3.icons.BaseIconFactory.IconOptions
+import com.android.launcher3.icons.BitmapInfo
+import com.android.launcher3.icons.mono.MonoIconThemeController
import com.android.launcher3.util.UserIconInfo
import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
@@ -55,6 +58,7 @@ interface AppIconProvider {
packageName: String,
context: Context,
withWorkProfileBadge: Boolean = false,
+ themed: Boolean = true,
): Drawable
/**
@@ -74,6 +78,26 @@ constructor(@ShadeDisplayAware private val sysuiContext: Context, dumpManager: D
dumpManager.registerNormalDumpable(TAG, this)
}
+ private class NotificationIcons(context: Context?, fillResIconDpi: Int, iconBitmapSize: Int) :
+ BaseIconFactory(context, fillResIconDpi, iconBitmapSize) {
+
+ init {
+ if (notificationsRedesignThemedAppIcons()) {
+ // Initialize the controller so that we can support themed icons.
+ mThemeController =
+ MonoIconThemeController(
+ colorProvider = { ctx ->
+ val res = ctx.resources
+ intArrayOf(
+ /* background */ res.getColor(R.color.materialColorPrimary),
+ /* icon */ res.getColor(R.color.materialColorSurfaceContainerHigh),
+ )
+ }
+ )
+ }
+ }
+ }
+
private val iconFactory: BaseIconFactory
get() {
val isLowRam = ActivityManager.isLowRamDeviceStatic()
@@ -83,7 +107,7 @@ constructor(@ShadeDisplayAware private val sysuiContext: Context, dumpManager: D
if (isLowRam) R.dimen.notification_small_icon_size_low_ram
else R.dimen.notification_small_icon_size
)
- return BaseIconFactory(sysuiContext, res.configuration.densityDpi, iconSize)
+ return NotificationIcons(sysuiContext, res.configuration.densityDpi, iconSize)
}
private val cache = NotifCollectionCache<Drawable>()
@@ -92,12 +116,15 @@ constructor(@ShadeDisplayAware private val sysuiContext: Context, dumpManager: D
packageName: String,
context: Context,
withWorkProfileBadge: Boolean,
+ themed: Boolean,
): Drawable {
// Add a suffix to distinguish the app installed on the work profile, since the icon will
// be different.
val key = packageName + if (withWorkProfileBadge) WORK_SUFFIX else ""
- return cache.getOrFetch(key) { fetchAppIcon(packageName, context, withWorkProfileBadge) }
+ return cache.getOrFetch(key) {
+ fetchAppIcon(packageName, context, withWorkProfileBadge, themed)
+ }
}
@WorkerThread
@@ -105,6 +132,7 @@ constructor(@ShadeDisplayAware private val sysuiContext: Context, dumpManager: D
packageName: String,
context: Context,
withWorkProfileBadge: Boolean,
+ themed: Boolean,
): Drawable {
val pm = context.packageManager
val icon = pm.getApplicationInfo(packageName, 0).loadUnbadgedIcon(pm)
@@ -113,13 +141,14 @@ constructor(@ShadeDisplayAware private val sysuiContext: Context, dumpManager: D
IconOptions().apply {
setUser(userIconInfo(context, withWorkProfileBadge))
setBitmapGenerationMode(BaseIconFactory.MODE_HARDWARE)
- // This color is not used since we're not showing the themed icons. We're just
- // setting it so that the icon factory doesn't try to extract colors from our bitmap
- // (since it won't work, given it's a hardware bitmap).
+ // This color will not be used, but we're just setting it so that the icon factory
+ // doesn't try to extract colors from our bitmap (since it won't work, given it's a
+ // hardware bitmap).
setExtractedColor(Color.BLUE)
}
val badgedIcon = iconFactory.createBadgedIconBitmap(icon, options)
- return badgedIcon.newIcon(sysuiContext)
+ val creationFlags = if (themed) BitmapInfo.FLAG_THEMED else 0
+ return badgedIcon.newIcon(sysuiContext, creationFlags)
}
private fun userIconInfo(context: Context, withWorkProfileBadge: Boolean): UserIconInfo {
@@ -165,6 +194,7 @@ class NoOpIconProvider : AppIconProvider {
packageName: String,
context: Context,
withWorkProfileBadge: Boolean,
+ themed: Boolean,
): Drawable {
Log.wtf(TAG, "NoOpIconProvider should not be used anywhere.")
return ColorDrawable(Color.WHITE)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/NotificationRowIconViewInflaterFactory.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/NotificationRowIconViewInflaterFactory.kt
index 64fdf6fc2708..bb4aa86fc6a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/NotificationRowIconViewInflaterFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/NotificationRowIconViewInflaterFactory.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.row.icon
+import android.app.Flags.notificationsRedesignThemedAppIcons
import android.content.Context
import android.graphics.drawable.Drawable
import android.util.AttributeSet
@@ -74,6 +75,7 @@ constructor(
sbn.packageName,
context,
withWorkProfileBadge,
+ themed = notificationsRedesignThemedAppIcons(),
)
}
}
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 76591ac4e453..495b50869458 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
@@ -98,6 +98,7 @@ import com.android.systemui.shade.QSHeaderBoundsProvider;
import com.android.systemui.shade.TouchLogger;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.headsup.shared.StatusBarNoHunBehavior;
import com.android.systemui.statusbar.notification.ColorUpdateLogger;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
@@ -512,23 +513,27 @@ public class NotificationStackScrollLayout
*/
private final Path mRoundedClipPath = new Path();
+ /** The clip path defining where we are NOT allowed to draw. */
+ private final Path mNegativeRoundedClipPath = new Path();
+
/**
* The clip Path used to clip the launching notification. This may be different
* from the normal path, as the views launch animation could start clipped.
*/
private final Path mLaunchedNotificationClipPath = new Path();
- /**
- * Should we use rounded rect clipping right now
- */
+ /** Should we use rounded rect clipping right now */
private boolean mShouldUseRoundedRectClipping = false;
+ /** Should we set an out path for the drawing canvas */
+ private boolean mShouldUseNegativeRoundedRectClipping = false;
+
private int mRoundedRectClippingLeft;
private int mRoundedRectClippingTop;
private int mRoundedRectClippingBottom;
private int mRoundedRectClippingRight;
private int mRoundedRectClippingYTranslation;
- private final float[] mBgCornerRadii = new float[8];
+ private final float[] mRoundedClipCornerRadii = new float[8];
/**
* Whether stackY should be animated in case the view is getting shorter than the scroll
@@ -1245,15 +1250,19 @@ public class NotificationStackScrollLayout
@Override
public void setHeadsUpTop(float headsUpTop) {
if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
- mAmbientState.setHeadsUpTop(headsUpTop);
- requestChildrenUpdate();
+ if (mAmbientState.getHeadsUpTop() != headsUpTop) {
+ mAmbientState.setHeadsUpTop(headsUpTop);
+ requestChildrenUpdate();
+ }
}
@Override
public void setHeadsUpBottom(float headsUpBottom) {
if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
- mAmbientState.setHeadsUpBottom(headsUpBottom);
- mStateAnimator.setHeadsUpAppearHeightBottom(Math.round(headsUpBottom));
+ if (mAmbientState.getHeadsUpBottom() != headsUpBottom) {
+ mAmbientState.setHeadsUpBottom(headsUpBottom);
+ mStateAnimator.setHeadsUpAppearHeightBottom(Math.round(headsUpBottom));
+ }
}
@Override
@@ -3860,7 +3869,7 @@ public class NotificationStackScrollLayout
if (!SceneContainerFlag.isEnabled()) {
return !isInsideQsHeader(ev);
}
- ShadeScrimShape shape = mScrollViewFields.getScrimClippingShape();
+ ShadeScrimShape shape = mScrollViewFields.getClippingShape();
if (shape == null) {
return true; // When there is no scrim, consider this event scrollable.
}
@@ -5331,7 +5340,7 @@ public class NotificationStackScrollLayout
void onStatePostChange(boolean fromShadeLocked) {
boolean onKeyguard = onKeyguard();
- if (mHeadsUpAppearanceController != null) {
+ if (mHeadsUpAppearanceController != null && !StatusBarNoHunBehavior.isEnabled()) {
mHeadsUpAppearanceController.onStateChanged();
}
@@ -5386,7 +5395,8 @@ public class NotificationStackScrollLayout
println(pw, "pulsing", mPulsing);
println(pw, "expanded", mIsExpanded);
println(pw, "headsUpPinned", mInHeadsUpPinnedMode);
- println(pw, "qsClipping", mShouldUseRoundedRectClipping);
+ println(pw, "roundedRectClipping", mShouldUseRoundedRectClipping);
+ println(pw, "negativeRoundedRectClipping", mShouldUseNegativeRoundedRectClipping);
println(pw, "qsClipDismiss", mDismissUsingRowTranslationX);
println(pw, "visibility", visibilityString(getVisibility()));
println(pw, "alpha", getAlpha());
@@ -5465,8 +5475,8 @@ public class NotificationStackScrollLayout
pw.append(" r=").print(mRoundedRectClippingRight);
pw.append(" b=").print(mRoundedRectClippingBottom);
pw.append(" +y=").print(mRoundedRectClippingYTranslation);
- pw.append("} topRadius=").print(mBgCornerRadii[0]);
- pw.append(" bottomRadius=").println(mBgCornerRadii[4]);
+ pw.append("} topRadius=").print(mRoundedClipCornerRadii[0]);
+ pw.append(" bottomRadius=").println(mRoundedClipCornerRadii[4]);
}
public boolean isFullyHidden() {
@@ -5913,14 +5923,12 @@ public class NotificationStackScrollLayout
mScrollListener = listener;
}
- /**
- * Set rounded rect clipping bounds on this view.
- */
+ /** Sets rounded rect where the view is allowed to draw. */
@Override
- public void setScrimClippingShape(@Nullable ShadeScrimShape shape) {
+ public void setClippingShape(@Nullable ShadeScrimShape shape) {
if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
- if (Objects.equals(mScrollViewFields.getScrimClippingShape(), shape)) return;
- mScrollViewFields.setScrimClippingShape(shape);
+ if (Objects.equals(mScrollViewFields.getClippingShape(), shape)) return;
+ mScrollViewFields.setClippingShape(shape);
mShouldUseRoundedRectClipping = shape != null;
mRoundedClipPath.reset();
if (shape != null) {
@@ -5929,17 +5937,36 @@ public class NotificationStackScrollLayout
mRoundedRectClippingTop = (int) bounds.getTop();
mRoundedRectClippingRight = (int) bounds.getRight();
mRoundedRectClippingBottom = (int) bounds.getBottom();
- mBgCornerRadii[0] = shape.getTopRadius();
- mBgCornerRadii[1] = shape.getTopRadius();
- mBgCornerRadii[2] = shape.getTopRadius();
- mBgCornerRadii[3] = shape.getTopRadius();
- mBgCornerRadii[4] = shape.getBottomRadius();
- mBgCornerRadii[5] = shape.getBottomRadius();
- mBgCornerRadii[6] = shape.getBottomRadius();
- mBgCornerRadii[7] = shape.getBottomRadius();
+ mRoundedClipCornerRadii[0] = shape.getTopRadius();
+ mRoundedClipCornerRadii[1] = shape.getTopRadius();
+ mRoundedClipCornerRadii[2] = shape.getTopRadius();
+ mRoundedClipCornerRadii[3] = shape.getTopRadius();
+ mRoundedClipCornerRadii[4] = shape.getBottomRadius();
+ mRoundedClipCornerRadii[5] = shape.getBottomRadius();
+ mRoundedClipCornerRadii[6] = shape.getBottomRadius();
+ mRoundedClipCornerRadii[7] = shape.getBottomRadius();
mRoundedClipPath.addRoundRect(
bounds.getLeft(), bounds.getTop(), bounds.getRight(), bounds.getBottom(),
- mBgCornerRadii, Path.Direction.CW);
+ mRoundedClipCornerRadii, Path.Direction.CW);
+ }
+ invalidate();
+ }
+
+ @Override
+ public void setNegativeClippingShape(@Nullable ShadeScrimShape shape) {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
+ if (Objects.equals(mScrollViewFields.getNegativeClippingShape(), shape)) return;
+
+ mScrollViewFields.setNegativeClippingShape(shape);
+ mShouldUseNegativeRoundedRectClipping = shape != null;
+ mNegativeRoundedClipPath.reset();
+ if (shape != null) {
+ ShadeScrimBounds bounds = shape.getBounds();
+ float bottomRadius = shape.getBottomRadius();
+ mNegativeRoundedClipPath.addRoundRect(
+ bounds.getLeft(), bounds.getTop(), bounds.getRight(), bounds.getBottom(),
+ new float[]{0, 0, 0, 0, bottomRadius, bottomRadius, bottomRadius, bottomRadius},
+ Path.Direction.CW);
}
invalidate();
}
@@ -5952,21 +5979,22 @@ public class NotificationStackScrollLayout
SceneContainerFlag.assertInLegacyMode();
if (mRoundedRectClippingLeft == left && mRoundedRectClippingRight == right
&& mRoundedRectClippingBottom == bottom && mRoundedRectClippingTop == top
- && mBgCornerRadii[0] == topRadius && mBgCornerRadii[5] == bottomRadius) {
+ && mRoundedClipCornerRadii[0] == topRadius
+ && mRoundedClipCornerRadii[5] == bottomRadius) {
return;
}
mRoundedRectClippingLeft = left;
mRoundedRectClippingTop = top;
mRoundedRectClippingBottom = bottom;
mRoundedRectClippingRight = right;
- mBgCornerRadii[0] = topRadius;
- mBgCornerRadii[1] = topRadius;
- mBgCornerRadii[2] = topRadius;
- mBgCornerRadii[3] = topRadius;
- mBgCornerRadii[4] = bottomRadius;
- mBgCornerRadii[5] = bottomRadius;
- mBgCornerRadii[6] = bottomRadius;
- mBgCornerRadii[7] = bottomRadius;
+ mRoundedClipCornerRadii[0] = topRadius;
+ mRoundedClipCornerRadii[1] = topRadius;
+ mRoundedClipCornerRadii[2] = topRadius;
+ mRoundedClipCornerRadii[3] = topRadius;
+ mRoundedClipCornerRadii[4] = bottomRadius;
+ mRoundedClipCornerRadii[5] = bottomRadius;
+ mRoundedClipCornerRadii[6] = bottomRadius;
+ mRoundedClipCornerRadii[7] = bottomRadius;
updateRoundedClipPath();
}
@@ -5988,7 +6016,7 @@ public class NotificationStackScrollLayout
mRoundedRectClippingTop + mRoundedRectClippingYTranslation,
mRoundedRectClippingRight,
mRoundedRectClippingBottom + mRoundedRectClippingYTranslation,
- mBgCornerRadii, Path.Direction.CW);
+ mRoundedClipCornerRadii, Path.Direction.CW);
if (mShouldUseRoundedRectClipping) {
invalidate();
}
@@ -6112,35 +6140,49 @@ public class NotificationStackScrollLayout
}
@Override
- protected void dispatchDraw(Canvas canvas) {
- if (mShouldUseRoundedRectClipping && !mLaunchingNotification) {
+ protected void dispatchDraw(@NonNull Canvas canvas) {
+ if (!mLaunchingNotification) {
// When launching notifications, we're clipping the children individually instead of in
// dispatchDraw
- // Let's clip rounded.
- canvas.clipPath(mRoundedClipPath);
+ if (mShouldUseRoundedRectClipping) {
+ // Let's clip rounded.
+ canvas.clipPath(mRoundedClipPath);
+ }
+ if (mShouldUseNegativeRoundedRectClipping) {
+ // subtract the negative path if it is defined
+ canvas.clipOutPath(mNegativeRoundedClipPath);
+ }
}
super.dispatchDraw(canvas);
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
- if (mShouldUseRoundedRectClipping && mLaunchingNotification) {
+ boolean shouldUseClipping =
+ mShouldUseRoundedRectClipping || mShouldUseNegativeRoundedRectClipping;
+ if (mLaunchingNotification && shouldUseClipping) {
// Let's clip children individually during notification launch
canvas.save();
ExpandableView expandableView = (ExpandableView) child;
Path clipPath;
+ Path clipOutPath;
if (expandableView.isExpandAnimationRunning()
|| ((ExpandableView) child).hasExpandingChild()) {
// When launching the notification, it is not clipped by this layout, but by the
// view itself. This is because the view is Translating in Z, where this clipPath
// wouldn't apply.
clipPath = null;
+ clipOutPath = null;
} else {
clipPath = mRoundedClipPath;
+ clipOutPath = mNegativeRoundedClipPath;
}
- if (clipPath != null) {
+ if (mShouldUseRoundedRectClipping && clipPath != null) {
canvas.clipPath(clipPath);
}
+ if (mShouldUseNegativeRoundedRectClipping && clipOutPath != null) {
+ canvas.clipOutPath(clipOutPath);
+ }
boolean result = super.drawChild(canvas, child, drawingTime);
canvas.restore();
return result;
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 c717e3b229be..dc0fae80d041 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
@@ -1207,7 +1207,11 @@ public class NotificationStackScrollLayoutController implements Dumpable {
return mView.getEmptyShadeViewHeight();
}
- /** Set the max alpha for keyguard */
+ /**
+ * Controls fading out Notifications during animations over the LockScreen, such opening or
+ * closing the shade. Note that we don't restrict Notification alpha in certain cases,
+ * like when the Shade is opened from a HUN.
+ */
public void setMaxAlphaForKeyguard(float alpha, String source) {
mMaxAlphaForKeyguard = alpha;
mMaxAlphaForKeyguardSource = source;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt
index fa20e43d0534..2593ef07751b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt
@@ -33,7 +33,10 @@ import java.util.function.Consumer
*/
class ScrollViewFields {
/** Used to produce the clipping path */
- var scrimClippingShape: ShadeScrimShape? = null
+ var clippingShape: ShadeScrimShape? = null
+
+ /** Used to produce a negative clipping path */
+ var negativeClippingShape: ShadeScrimShape? = null
/** Scroll state of the notification shade. */
var scrollState: ShadeScrollState = ShadeScrollState()
@@ -97,7 +100,8 @@ class ScrollViewFields {
fun dump(pw: IndentingPrintWriter) {
pw.printSection("StackViewStates") {
- pw.println("scrimClippingShape", scrimClippingShape)
+ pw.println("scrimClippingShape", clippingShape)
+ pw.println("negativeClippingShape", negativeClippingShape)
pw.println("scrollState", scrollState)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationPlaceholderRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationPlaceholderRepository.kt
index 5ec4c8988697..1d196c2fc079 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationPlaceholderRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationPlaceholderRepository.kt
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification.stack.data.repository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.notification.stack.shared.model.AccessibilityScrollEvent
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds
+import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrollState
import java.util.function.Consumer
import javax.inject.Inject
@@ -42,7 +43,15 @@ class NotificationPlaceholderRepository @Inject constructor() {
*
* When `null`, clipping should not be applied to notifications.
*/
- val shadeScrimBounds = MutableStateFlow<ShadeScrimBounds?>(null)
+ val notificationShadeScrimBounds = MutableStateFlow<ShadeScrimBounds?>(null)
+
+ /**
+ * The shape of the QuickSettings overlay panel. Used to clip Notification content when the QS
+ * covers it.
+ *
+ * When `null`, it doesn't affect notification clipping.
+ */
+ val qsPanelShape = MutableStateFlow<ShadeScrimShape?>(null)
/** height made available to the notifications in the size-constrained mode of lock screen. */
val constrainedAvailableSpace = MutableStateFlow(0)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
index d4dd1d4b9e0b..406a0dbb120f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
@@ -26,6 +26,7 @@ import com.android.systemui.statusbar.notification.stack.data.repository.Notific
import com.android.systemui.statusbar.notification.stack.shared.model.AccessibilityScrollEvent
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimRounding
+import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrollState
import java.util.function.Consumer
import javax.inject.Inject
@@ -47,8 +48,11 @@ constructor(
shadeInteractor: ShadeInteractor,
) {
/** The bounds of the notification stack in the current scene. */
- val shadeScrimBounds: StateFlow<ShadeScrimBounds?> =
- placeholderRepository.shadeScrimBounds.asStateFlow()
+ val notificationShadeScrimBounds: StateFlow<ShadeScrimBounds?> =
+ placeholderRepository.notificationShadeScrimBounds.asStateFlow()
+
+ /** The shape of the QuickSettingsShadeOverlay panel */
+ val qsPanelShape: StateFlow<ShadeScrimShape?> = placeholderRepository.qsPanelShape.asStateFlow()
/**
* Whether the stack is expanding from GONE-with-HUN to SHADE
@@ -119,9 +123,15 @@ constructor(
}
/** Sets the position of the notification stack in the current scene. */
- fun setShadeScrimBounds(bounds: ShadeScrimBounds?) {
- check(bounds == null || bounds.top <= bounds.bottom) { "Invalid bounds: $bounds" }
- placeholderRepository.shadeScrimBounds.value = bounds
+ fun setNotificationShadeScrimBounds(bounds: ShadeScrimBounds?) {
+ checkValidBounds(bounds)
+ placeholderRepository.notificationShadeScrimBounds.value = bounds
+ }
+
+ /** Sets the bounds of the QuickSettings overlay panel */
+ fun setQsPanelShape(shape: ShadeScrimShape?) {
+ checkValidBounds(shape?.bounds)
+ placeholderRepository.qsPanelShape.value = shape
}
/** Updates the current scroll state of the notification shade. */
@@ -156,4 +166,8 @@ constructor(
fun setConstrainedAvailableSpace(height: Int) {
placeholderRepository.constrainedAvailableSpace.value = height
}
+
+ private fun checkValidBounds(bounds: ShadeScrimBounds?) {
+ check(bounds == null || bounds.top <= bounds.bottom) { "Invalid bounds: $bounds" }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
index d302fb67dddb..5fec0965f6a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
@@ -49,8 +49,14 @@ interface NotificationScrollView {
/** Max alpha for this view */
fun setMaxAlpha(alpha: Float)
- /** Set the clipping bounds used when drawing */
- fun setScrimClippingShape(shape: ShadeScrimShape?)
+ /** Sets a clipping shape, which defines the drawable area of this view. */
+ fun setClippingShape(shape: ShadeScrimShape?)
+
+ /**
+ * Sets a clipping shape, which defines the non-drawable area of this view. The final drawing
+ * area is the difference of the clipping shape, and the negative clipping shape.
+ */
+ fun setNegativeClippingShape(shape: ShadeScrimShape?)
/** set the y position in px of the top of the stack in this view's coordinates */
fun setStackTop(stackTop: Float)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
index 1d7e658932ac..6385d53dbc8b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
@@ -99,6 +99,9 @@ constructor(
.inflate(R.layout.status_bar_notification_shelf, view, false) as NotificationShelf
view.setShelf(shelf)
+ // Create viewModels once, and only when needed.
+ val footerViewModel by lazy { viewModel.footerViewModelFactory.create() }
+ val emptyShadeViewModel by lazy { viewModel.emptyShadeViewModelFactory.create() }
view.repeatWhenAttached {
lifecycleScope.launch {
if (SceneContainerFlag.isEnabled) {
@@ -109,12 +112,18 @@ constructor(
val hasNonClearableSilentNotifications: StateFlow<Boolean> =
viewModel.hasNonClearableSilentNotifications.stateIn(this)
- launch { reinflateAndBindFooter(view, hasNonClearableSilentNotifications) }
+ launch {
+ reinflateAndBindFooter(
+ footerViewModel,
+ view,
+ hasNonClearableSilentNotifications,
+ )
+ }
launch {
if (ModesEmptyShadeFix.isEnabled) {
- reinflateAndBindEmptyShade(view)
+ reinflateAndBindEmptyShade(emptyShadeViewModel, view)
} else {
- bindEmptyShadeLegacy(viewModel.emptyShadeViewFactory.create(), view)
+ bindEmptyShadeLegacy(emptyShadeViewModel, view)
}
}
launch { bindSilentHeaderClickListener(view, hasNonClearableSilentNotifications) }
@@ -134,31 +143,30 @@ constructor(
}
private suspend fun reinflateAndBindFooter(
+ footerViewModel: FooterViewModel,
parentView: NotificationStackScrollLayout,
hasNonClearableSilentNotifications: StateFlow<Boolean>,
) {
- viewModel.footer.getOrNull()?.let { footerViewModel ->
- // The footer needs to be re-inflated every time the theme or the font size changes.
- configuration
- .inflateLayout<FooterView>(
- if (NotifRedesignFooter.isEnabled) R.layout.notification_2025_footer
- else R.layout.status_bar_notification_footer,
- parentView,
- attachToRoot = false,
- )
- .flowOn(backgroundDispatcher)
- .collectLatest { footerView: FooterView ->
- traceAsync("bind FooterView") {
- parentView.setFooterView(footerView)
- bindFooter(
- footerView,
- footerViewModel,
- parentView,
- hasNonClearableSilentNotifications,
- )
- }
+ // The footer needs to be re-inflated every time the theme or the font size changes.
+ configuration
+ .inflateLayout<FooterView>(
+ if (NotifRedesignFooter.isEnabled) R.layout.notification_2025_footer
+ else R.layout.status_bar_notification_footer,
+ parentView,
+ attachToRoot = false,
+ )
+ .flowOn(backgroundDispatcher)
+ .collectLatest { footerView: FooterView ->
+ traceAsync("bind FooterView") {
+ parentView.setFooterView(footerView)
+ bindFooter(
+ footerView,
+ footerViewModel,
+ parentView,
+ hasNonClearableSilentNotifications,
+ )
}
- }
+ }
}
/**
@@ -219,7 +227,10 @@ constructor(
notificationActivityStarter.get().startHistoryIntent(view, /* showHistory= */ true)
}
- private suspend fun reinflateAndBindEmptyShade(parentView: NotificationStackScrollLayout) {
+ private suspend fun reinflateAndBindEmptyShade(
+ emptyShadeViewModel: EmptyShadeViewModel,
+ parentView: NotificationStackScrollLayout,
+ ) {
ModesEmptyShadeFix.assertInNewMode()
// The empty shade needs to be re-inflated every time the theme or the font size
// changes.
@@ -233,7 +244,7 @@ constructor(
.collectLatest { emptyShadeView: EmptyShadeView ->
traceAsync("bind EmptyShadeView") {
parentView.setEmptyShadeView(emptyShadeView)
- bindEmptyShade(emptyShadeView, viewModel.emptyShadeViewFactory.create())
+ bindEmptyShade(emptyShadeView, emptyShadeViewModel)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
index ef68b4de5291..8709d27bddcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
@@ -79,8 +79,17 @@ constructor(
launch {
viewModel
- .shadeScrimShape(cornerRadius = scrimRadius, viewLeftOffset = viewLeftOffset)
- .collectTraced { view.setScrimClippingShape(it) }
+ .notificationScrimShape(
+ cornerRadius = scrimRadius,
+ viewLeftOffset = viewLeftOffset,
+ )
+ .collectTraced { view.setClippingShape(it) }
+ }
+
+ launch {
+ viewModel.qsScrimShape(viewLeftOffset = viewLeftOffset).collectTraced {
+ view.setNegativeClippingShape(it)
+ }
}
launch { viewModel.maxAlpha.collectTraced { view.setMaxAlpha(it) } }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
index fcc671a5bae6..5ed1889de01e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
@@ -56,8 +56,8 @@ class NotificationListViewModel
constructor(
val shelf: NotificationShelfViewModel,
val hideListViewModel: HideListViewModel,
- val footer: Optional<FooterViewModel>,
- val emptyShadeViewFactory: EmptyShadeViewModel.Factory,
+ val footerViewModelFactory: FooterViewModel.Factory,
+ val emptyShadeViewModelFactory: EmptyShadeViewModel.Factory,
val logger: Optional<NotificationLoggerViewModel>,
activeNotificationsInteractor: ActiveNotificationsInteractor,
notificationStackInteractor: NotificationStackInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
index 1bb205cbcb61..80ebf43baf92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
@@ -59,7 +59,7 @@ class NotificationScrollViewModel
@AssistedInject
constructor(
dumpManager: DumpManager,
- stackAppearanceInteractor: NotificationStackAppearanceInteractor,
+ private val stackAppearanceInteractor: NotificationStackAppearanceInteractor,
shadeInteractor: ShadeInteractor,
private val remoteInputInteractor: RemoteInputInteractor,
private val sceneInteractor: SceneInteractor,
@@ -221,7 +221,7 @@ constructor(
private val shadeScrimClipping: Flow<ShadeScrimClipping?> =
combine(
qsAllowsClipping,
- stackAppearanceInteractor.shadeScrimBounds,
+ stackAppearanceInteractor.notificationShadeScrimBounds,
stackAppearanceInteractor.shadeScrimRounding,
) { qsAllowsClipping, bounds, rounding ->
bounds?.takeIf { qsAllowsClipping }?.let { ShadeScrimClipping(it, rounding) }
@@ -229,7 +229,7 @@ constructor(
.distinctUntilChanged()
.dumpWhileCollecting("stackClipping")
- fun shadeScrimShape(
+ fun notificationScrimShape(
cornerRadius: Flow<Int>,
viewLeftOffset: Flow<Int>,
): Flow<ShadeScrimShape?> =
@@ -243,6 +243,12 @@ constructor(
}
.dumpWhileCollecting("shadeScrimShape")
+ fun qsScrimShape(viewLeftOffset: Flow<Int>): Flow<ShadeScrimShape?> =
+ combine(stackAppearanceInteractor.qsPanelShape, viewLeftOffset) { shape, leftOffset ->
+ shape?.let { it.copy(bounds = it.bounds.minus(leftOffset = leftOffset)) }
+ }
+ .dumpWhileCollecting("qsScrimShape")
+
/**
* Max alpha to apply directly to the view based on the compose placeholder.
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
index 49cd7cb4fb8d..8e12e081e861 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
@@ -16,14 +16,21 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
+import androidx.compose.runtime.getValue
+import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.lifecycle.ExclusiveActivatable
+import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.domain.interactor.RemoteInputInteractor
import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackAppearanceInteractor
@@ -40,7 +47,6 @@ import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
-import com.android.app.tracing.coroutines.launchTraced as launch
/**
* ViewModel used by the Notification placeholders inside the scene container to update the
@@ -63,6 +69,24 @@ constructor(
tag = "NotificationsPlaceholderViewModel",
) {
+ private val hydrator = Hydrator("NotificationsPlaceholderViewModel")
+
+ /** The content key to use for the notification shade. */
+ val notificationsShadeContentKey: ContentKey by
+ hydrator.hydratedStateOf(
+ traceName = "notificationsShadeContentKey",
+ initialValue = getNotificationsShadeContentKey(shadeInteractor.shadeMode.value),
+ source = shadeInteractor.shadeMode.map { getNotificationsShadeContentKey(it) },
+ )
+
+ /** The content key to use for the quick settings shade. */
+ val quickSettingsShadeContentKey: ContentKey by
+ hydrator.hydratedStateOf(
+ traceName = "quickSettingsShadeContentKey",
+ initialValue = getQuickSettingsShadeContentKey(shadeInteractor.shadeMode.value),
+ source = shadeInteractor.shadeMode.map { getQuickSettingsShadeContentKey(it) },
+ )
+
/** DEBUG: whether the placeholder should be made slightly visible for positional debugging. */
val isVisualDebuggingEnabled: Boolean = featureFlags.isEnabled(Flags.NSSL_DEBUG_LINES)
@@ -71,6 +95,8 @@ constructor(
override suspend fun onActivated(): Nothing {
coroutineScope {
+ launch { hydrator.activate() }
+
launch {
shadeInteractor.isAnyExpanded
.filter { it }
@@ -79,8 +105,7 @@ constructor(
launch {
sceneInteractor.transitionState
- .map { state -> state is ObservableTransitionState.Idle }
- .filter { it }
+ .filter { it is ObservableTransitionState.Idle }
.collect { headsUpNotificationInteractor.onTransitionIdle() }
}
}
@@ -89,7 +114,7 @@ constructor(
/** Notifies that the bounds of the notification scrim have changed. */
fun onScrimBoundsChanged(bounds: ShadeScrimBounds?) {
- interactor.setShadeScrimBounds(bounds)
+ interactor.setNotificationShadeScrimBounds(bounds)
}
/** Sets the available space */
@@ -163,6 +188,18 @@ constructor(
interactor.setAccessibilityScrollEventConsumer(consumer)
}
+ private fun getNotificationsShadeContentKey(shadeMode: ShadeMode): ContentKey {
+ return if (shadeMode is ShadeMode.Dual) Overlays.NotificationsShade else Scenes.Shade
+ }
+
+ private fun getQuickSettingsShadeContentKey(shadeMode: ShadeMode): ContentKey {
+ return when (shadeMode) {
+ is ShadeMode.Single -> Scenes.QuickSettings
+ is ShadeMode.Split -> Scenes.Shade
+ is ShadeMode.Dual -> Overlays.QuickSettingsShade
+ }
+ }
+
@AssistedFactory
interface Factory {
fun create(): NotificationsPlaceholderViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 53a29505510b..548ab8311144 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -39,6 +39,7 @@ import com.android.systemui.statusbar.HeadsUpStatusBarView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
import com.android.systemui.statusbar.core.StatusBarRootModernization;
+import com.android.systemui.statusbar.headsup.shared.StatusBarNoHunBehavior;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.SourceType;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -151,19 +152,21 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
mOperatorNameViewOptional = operatorNameViewOptional;
mDarkIconDispatcher = darkIconDispatcher;
- mView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- if (shouldHeadsUpStatusBarBeVisible()) {
- updateTopEntry();
-
- // trigger scroller to notify the latest panel translation
- mStackScrollerController.requestLayout();
+ if (!StatusBarNoHunBehavior.isEnabled()) {
+ mView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ if (shouldHeadsUpStatusBarBeVisible()) {
+ updatePinnedStatus();
+
+ // trigger scroller to notify the latest panel translation
+ mStackScrollerController.requestLayout();
+ }
+ mView.removeOnLayoutChangeListener(this);
}
- mView.removeOnLayoutChangeListener(this);
- }
- });
+ });
+ }
mBypassController = bypassController;
mStatusBarStateController = stateController;
mPhoneStatusBarTransitions = phoneStatusBarTransitions;
@@ -175,13 +178,15 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
@Override
protected void onViewAttached() {
mHeadsUpManager.addListener(this);
- mView.setOnDrawingRectChangedListener(this::updateIsolatedIconLocation);
- updateIsolatedIconLocation();
- mWakeUpCoordinator.addListener(this);
+ if (!StatusBarNoHunBehavior.isEnabled()) {
+ mView.setOnDrawingRectChangedListener(this::updateIsolatedIconLocation);
+ updateIsolatedIconLocation();
+ mDarkIconDispatcher.addDarkReceiver(this);
+ mWakeUpCoordinator.addListener(this);
+ }
getShadeHeadsUpTracker().addTrackingHeadsUpListener(mSetTrackingHeadsUp);
getShadeHeadsUpTracker().setHeadsUpAppearanceController(this);
mStackScrollerController.addOnExpandedHeightChangedListener(mSetExpandedHeight);
- mDarkIconDispatcher.addDarkReceiver(this);
}
private ShadeHeadsUpTracker getShadeHeadsUpTracker() {
@@ -191,22 +196,25 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
@Override
protected void onViewDetached() {
mHeadsUpManager.removeListener(this);
- mView.setOnDrawingRectChangedListener(null);
- mHeadsUpNotificationIconInteractor.setIsolatedIconLocation(null);
- mWakeUpCoordinator.removeListener(this);
+ if (!StatusBarNoHunBehavior.isEnabled()) {
+ mView.setOnDrawingRectChangedListener(null);
+ mHeadsUpNotificationIconInteractor.setIsolatedIconLocation(null);
+ mDarkIconDispatcher.removeDarkReceiver(this);
+ mWakeUpCoordinator.removeListener(this);
+ }
getShadeHeadsUpTracker().removeTrackingHeadsUpListener(mSetTrackingHeadsUp);
getShadeHeadsUpTracker().setHeadsUpAppearanceController(null);
mStackScrollerController.removeOnExpandedHeightChangedListener(mSetExpandedHeight);
- mDarkIconDispatcher.removeDarkReceiver(this);
}
private void updateIsolatedIconLocation() {
+ StatusBarNoHunBehavior.assertInLegacyMode();
mHeadsUpNotificationIconInteractor.setIsolatedIconLocation(mView.getIconDrawingRect());
}
@Override
public void onHeadsUpPinned(NotificationEntry entry) {
- updateTopEntry();
+ updatePinnedStatus();
updateHeader(entry);
updateHeadsUpAndPulsingRoundness(entry);
}
@@ -217,7 +225,10 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
mPhoneStatusBarTransitions.onHeadsUpStateChanged(isHeadsUp);
}
- private void updateTopEntry() {
+ private void updatePinnedStatus() {
+ if (StatusBarNoHunBehavior.isEnabled()) {
+ return;
+ }
NotificationEntry newEntry = null;
if (shouldHeadsUpStatusBarBeVisible()) {
newEntry = mHeadsUpManager.getTopEntry();
@@ -239,6 +250,7 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
}
private static @Nullable String getIsolatedIconKey(NotificationEntry newEntry) {
+ StatusBarNoHunBehavior.assertInLegacyMode();
if (newEntry == null) {
return null;
}
@@ -259,6 +271,9 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
}
private void setPinnedStatus(PinnedStatus pinnedStatus) {
+ if (StatusBarNoHunBehavior.isEnabled()) {
+ return;
+ }
if (mPinnedStatus != pinnedStatus) {
mPinnedStatus = pinnedStatus;
@@ -292,6 +307,7 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
}
private void updateParentClipping(boolean shouldClip) {
+ StatusBarNoHunBehavior.assertInLegacyMode();
ViewClippingUtil.setClippingDeactivated(
mView, !shouldClip, mParentClippingParams);
}
@@ -319,6 +335,8 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
*
*/
private void hide(View view, int endState, Runnable callback) {
+ StatusBarNoHunBehavior.assertInLegacyMode();
+
if (mAnimationsEnabled) {
CrossFadeHelper.fadeOut(view, CONTENT_FADE_DURATION /* duration */,
0 /* delay */, () -> {
@@ -336,6 +354,8 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
}
private void show(View view) {
+ StatusBarNoHunBehavior.assertInLegacyMode();
+
if (mAnimationsEnabled) {
CrossFadeHelper.fadeIn(view, CONTENT_FADE_DURATION /* duration */,
CONTENT_FADE_DELAY /* delay */);
@@ -351,6 +371,9 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
@VisibleForTesting
public PinnedStatus getPinnedStatus() {
+ if (StatusBarNoHunBehavior.isEnabled()) {
+ return PinnedStatus.NotPinned;
+ }
return mPinnedStatus;
}
@@ -375,6 +398,10 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
*/
@Deprecated
public boolean shouldHeadsUpStatusBarBeVisible() {
+ if (StatusBarNoHunBehavior.isEnabled()) {
+ return false;
+ }
+
if (StatusBarNotifChips.isEnabled()) {
return canShowHeadsUp()
&& mHeadsUpManager.pinnedHeadsUpStatus() == PinnedStatus.PinnedBySystem;
@@ -388,7 +415,7 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
@Override
public void onHeadsUpUnPinned(NotificationEntry entry) {
- updateTopEntry();
+ updatePinnedStatus();
updateHeader(entry);
updateHeadsUpAndPulsingRoundness(entry);
}
@@ -406,7 +433,7 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
updateHeadsUpHeaders();
}
if (isExpanded() != oldIsExpanded) {
- updateTopEntry();
+ updatePinnedStatus();
}
}
@@ -476,15 +503,18 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
@Override
public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) {
+ StatusBarNoHunBehavior.assertInLegacyMode();
mView.onDarkChanged(areas, darkIntensity, tint);
}
public void onStateChanged() {
- updateTopEntry();
+ StatusBarNoHunBehavior.assertInLegacyMode();
+ updatePinnedStatus();
}
@Override
public void onFullyHiddenChanged(boolean isFullyHidden) {
- updateTopEntry();
+ StatusBarNoHunBehavior.assertInLegacyMode();
+ updatePinnedStatus();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index c396512ce3a5..1a97ab635028 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -41,6 +41,7 @@ import com.android.internal.statusbar.StatusBarIcon;
import com.android.settingslib.Utils;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.headsup.shared.StatusBarNoHunBehavior;
import com.android.systemui.statusbar.notification.stack.AnimationFilter;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.ViewState;
@@ -163,12 +164,12 @@ public class NotificationIconContainer extends ViewGroup {
private IconState mFirstVisibleIconState;
private float mVisualOverflowStart;
private boolean mIsShowingOverflowDot;
- private StatusBarIconView mIsolatedIcon;
- private Rect mIsolatedIconLocation;
+ @Nullable private StatusBarIconView mIsolatedIcon;
+ @Nullable private Rect mIsolatedIconLocation;
private final int[] mAbsolutePosition = new int[2];
- private View mIsolatedIconForAnimation;
+ @Nullable private View mIsolatedIconForAnimation;
private int mThemedTextColorPrimary;
- private Runnable mIsolatedIconAnimationEndRunnable;
+ @Nullable private Runnable mIsolatedIconAnimationEndRunnable;
private boolean mUseIncreasedIconScale;
public NotificationIconContainer(Context context, AttributeSet attrs) {
@@ -379,6 +380,9 @@ public class NotificationIconContainer extends ViewGroup {
if (areAnimationsEnabled(icon) && !isReplacingIcon) {
addTransientView(icon, 0);
boolean isIsolatedIcon = child == mIsolatedIcon;
+ if (StatusBarNoHunBehavior.isEnabled()) {
+ isIsolatedIcon = false;
+ }
icon.setVisibleState(StatusBarIconView.STATE_HIDDEN, true /* animate */,
() -> removeTransientView(icon),
isIsolatedIcon ? CONTENT_FADE_DURATION : 0);
@@ -539,7 +543,7 @@ public class NotificationIconContainer extends ViewGroup {
iconState.setXTranslation(getRtlIconTranslationX(iconState, view));
}
}
- if (mIsolatedIcon != null) {
+ if (!StatusBarNoHunBehavior.isEnabled() && mIsolatedIcon != null) {
IconState iconState = mIconStates.get(mIsolatedIcon);
if (iconState != null) {
// Most of the time the icon isn't yet added when this is called but only happening
@@ -685,17 +689,20 @@ public class NotificationIconContainer extends ViewGroup {
public void showIconIsolatedAnimated(StatusBarIconView icon,
@Nullable Runnable onAnimationEnd) {
+ StatusBarNoHunBehavior.assertInLegacyMode();
mIsolatedIconForAnimation = icon != null ? icon : mIsolatedIcon;
mIsolatedIconAnimationEndRunnable = onAnimationEnd;
showIconIsolated(icon);
}
public void showIconIsolated(StatusBarIconView icon) {
+ StatusBarNoHunBehavior.assertInLegacyMode();
mIsolatedIcon = icon;
updateState();
}
public void setIsolatedIconLocation(Rect isolatedIconLocation, boolean requireUpdate) {
+ StatusBarNoHunBehavior.assertInLegacyMode();
mIsolatedIconLocation = isolatedIconLocation;
if (requireUpdate) {
updateState();
@@ -794,7 +801,7 @@ public class NotificationIconContainer extends ViewGroup {
animationProperties.setDuration(CANNED_ANIMATION_DURATION);
animate = true;
}
- if (mIsolatedIconForAnimation != null) {
+ if (!StatusBarNoHunBehavior.isEnabled() && mIsolatedIconForAnimation != null) {
if (view == mIsolatedIconForAnimation) {
animationProperties = UNISOLATION_PROPERTY;
animationProperties.setDelay(
@@ -843,6 +850,7 @@ public class NotificationIconContainer extends ViewGroup {
@Nullable
private Consumer<Property> getEndAction() {
+ if (StatusBarNoHunBehavior.isEnabled()) return null;
if (mIsolatedIconAnimationEndRunnable == null) return null;
final Runnable endRunnable = mIsolatedIconAnimationEndRunnable;
return prop -> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index aa1308931f99..3f44f7bdef90 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -234,7 +234,7 @@ private constructor(
)
}
if (ShadeWindowGoesAround.isEnabled && event.action == MotionEvent.ACTION_DOWN) {
- lazyStatusBarShadeDisplayPolicy.get().onStatusBarTouched(context.displayId)
+ lazyStatusBarShadeDisplayPolicy.get().onStatusBarTouched(event, mView.width)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index c47ed1722bb4..fcc3af6a2134 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -397,6 +397,13 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
mDelegate.onWindowFocusChanged(this, hasFocus);
+ if (hasFocus) {
+ // Update SysUI state to reflect that a dialog is showing. This ensures the state is
+ // correct when this dialog regains focus after another dialog was closed.
+ // See b/386871258
+ mSysUiState.setFlag(QuickStepContract.SYSUI_STATE_DIALOG_SHOWING, true)
+ .commitUpdate(mContext.getDisplayId());
+ }
}
public void setShowForAllUsers(boolean show) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 1f1be261a854..c541cff4448c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -65,6 +65,7 @@ import com.android.systemui.statusbar.data.repository.StatusBarConfigurationCont
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
+import com.android.systemui.statusbar.headsup.shared.StatusBarNoHunBehavior;
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
import com.android.systemui.statusbar.phone.PhoneStatusBarView;
@@ -676,6 +677,11 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
boolean headsUpVisible = mHomeStatusBarComponent
.getHeadsUpAppearanceController()
.shouldHeadsUpStatusBarBeVisible();
+ if (StatusBarNoHunBehavior.isEnabled()) {
+ // With this flag enabled, we have no custom HUN behavior, so just always consider it
+ // to be not visible.
+ headsUpVisible = false;
+ }
if (SceneContainerFlag.isEnabled()) {
// With the scene container, only use the value calculated by the view model to
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 4eb69babfadb..a29934fa3a16 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -39,6 +39,7 @@ import com.android.systemui.statusbar.chips.ui.view.ChipChronometer
import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore
import com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureHandler
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
import com.android.systemui.statusbar.notification.shared.CallType
import com.android.systemui.statusbar.phone.ongoingcall.data.repository.OngoingCallRepository
@@ -159,6 +160,7 @@ constructor(
notificationIconView = currentInfo.notificationIconView,
intent = currentInfo.intent,
notificationKey = currentInfo.key,
+ promotedContent = currentInfo.promotedContent,
)
} else {
return OngoingCallModel.NoCall
@@ -215,6 +217,7 @@ constructor(
notifModel.statusBarChipIconView,
notifModel.contentIntent,
notifModel.uid,
+ notifModel.promotedContent,
isOngoing = true,
statusBarSwipedAway = callNotificationInfo?.statusBarSwipedAway ?: false,
)
@@ -334,6 +337,11 @@ constructor(
val notificationIconView: StatusBarIconView?,
val intent: PendingIntent?,
val uid: Int,
+ /**
+ * If the call notification also meets promoted notification criteria, this field is filled
+ * in with the content related to promotion. Otherwise null.
+ */
+ val promotedContent: PromotedNotificationContentModel?,
/** True if the call is currently ongoing (as opposed to incoming, screening, etc.). */
val isOngoing: Boolean,
/** True if the user has swiped away the status bar while in this phone call. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt
index 2bfbf4826053..99141f592a2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt
@@ -165,6 +165,7 @@ constructor(
notificationIconView = model.statusBarChipIconView,
intent = model.contentIntent,
notificationKey = model.key,
+ promotedContent = model.promotedContent,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt
index 1a5dcc16f3db..7d00e9d58e5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone.ongoingcall.shared.model
import android.app.PendingIntent
import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
/** Represents the state of any ongoing calls. */
sealed interface OngoingCallModel {
@@ -25,8 +26,8 @@ sealed interface OngoingCallModel {
data object NoCall : OngoingCallModel
/**
- * There is an ongoing call but the call app is currently visible, so we don't need to show
- * the chip.
+ * There is an ongoing call but the call app is currently visible, so we don't need to show the
+ * chip.
*/
data object InCallWithVisibleApp : OngoingCallModel
@@ -41,11 +42,14 @@ sealed interface OngoingCallModel {
* @property notificationIconView the [android.app.Notification.getSmallIcon] that's set on the
* call notification. We may use this icon in the chip instead of the default phone icon.
* @property intent the intent associated with the call notification.
+ * @property promotedContent if the call notification also meets promoted notification criteria,
+ * this field is filled in with the content related to promotion. Otherwise null.
*/
data class InCall(
val startTimeMs: Long,
val notificationIconView: StatusBarIconView?,
val intent: PendingIntent?,
val notificationKey: String,
+ val promotedContent: PromotedNotificationContentModel?,
) : OngoingCallModel
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt
index 30c529a9034a..3e7094a0b5e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt
@@ -34,6 +34,9 @@ interface CarrierConfigRepository {
*/
suspend fun startObservingCarrierConfigUpdates()
- /** Gets a cached [SystemUiCarrierConfig], or creates a new one which will track the defaults */
- fun getOrCreateConfigForSubId(subId: Int): SystemUiCarrierConfig
+ /**
+ * Gets a cached [SystemUiCarrierConfig], or creates a new one which will track the defaults. A
+ * null [maybeSubId] will return the default carrier config.
+ */
+ fun getOrCreateConfigForSubId(maybeSubId: Int?): SystemUiCarrierConfig
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImpl.kt
index 9a97f19f6593..dacb859967e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImpl.kt
@@ -20,6 +20,7 @@ import android.content.IntentFilter
import android.os.PersistableBundle
import android.telephony.CarrierConfigManager
import android.telephony.SubscriptionManager
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import android.util.SparseArray
import androidx.annotation.VisibleForTesting
import androidx.core.util.getOrElse
@@ -51,7 +52,7 @@ constructor(
private val defaultConfig: PersistableBundle by lazy { CarrierConfigManager.getDefaultConfig() }
// Used for logging the default config in the dumpsys
private val defaultConfigForLogs: SystemUiCarrierConfig by lazy {
- SystemUiCarrierConfig(-1, defaultConfig)
+ SystemUiCarrierConfig(INVALID_SUBSCRIPTION_ID, defaultConfig)
}
private val configs = SparseArray<SystemUiCarrierConfig>()
@@ -89,7 +90,10 @@ constructor(
configToUpdate.processNewCarrierConfig(config)
}
- override fun getOrCreateConfigForSubId(subId: Int): SystemUiCarrierConfig {
+ override fun getOrCreateConfigForSubId(maybeSubId: Int?): SystemUiCarrierConfig {
+ // See CarrierConfigManager#getConfigForSubId(), passing INVALID_SUBSCRIPTION_ID yields
+ // the default carrier config
+ val subId = maybeSubId ?: INVALID_SUBSCRIPTION_ID
return configs.getOrElse(subId) {
val config = SystemUiCarrierConfig(subId, defaultConfig)
val carrierConfig = carrierConfigManager?.getConfigForSubId(subId)
@@ -107,7 +111,12 @@ constructor(
pw.println("Carrier configs by subId")
configs.keyIterator().forEach {
pw.println(" subId=$it")
- pw.println(" config=${configs.get(it).toStringConsideringDefaults()}")
+ val config = configs.get(it)
+ if (config == null) {
+ pw.println(" config=null (config was removed during dump)")
+ } else {
+ pw.println(" config=${config.toStringConsideringDefaults()}")
+ }
}
// Finally, print the default config
pw.println("Default config:")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
index 32e9c85bea81..09a626940c79 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
@@ -48,8 +48,8 @@ interface MobileConnectionsRepository {
*/
val activeSubChangedInGroupEvent: Flow<Unit>
- /** Tracks [SubscriptionManager.getDefaultDataSubscriptionId] */
- val defaultDataSubId: StateFlow<Int>
+ /** Tracks [SubscriptionManager.getDefaultDataSubscriptionId]. Null if there is no default */
+ val defaultDataSubId: StateFlow<Int?>
/**
* True if the default network connection is a mobile-like connection and false otherwise.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
index fc766915e4ef..252ebe6a32b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
@@ -164,7 +164,7 @@ constructor(
override fun getIsAnySimSecure(): Boolean = activeRepo.value.getIsAnySimSecure()
- override val defaultDataSubId: StateFlow<Int> =
+ override val defaultDataSubId: StateFlow<Int?> =
activeRepo
.flatMapLatest { it.defaultDataSubId }
.stateIn(scope, SharingStarted.WhileSubscribed(), realRepository.defaultDataSubId.value)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
index 936954f3b484..b608e53b4bce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
@@ -166,7 +166,7 @@ constructor(
private fun <K, V> Map<K, V>.reverse() = entries.associateBy({ it.value }) { it.key }
// TODO(b/261029387): add a command for this value
- override val defaultDataSubId = MutableStateFlow(INVALID_SUBSCRIPTION_ID)
+ override val defaultDataSubId: MutableStateFlow<Int?> = MutableStateFlow(null)
// TODO(b/261029387): not yet supported
override val mobileIsDefault: StateFlow<Boolean> = MutableStateFlow(true)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index b762751ecbb4..aa6da61958e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -249,7 +249,7 @@ constructor(
tableLogger,
LOGGING_PREFIX,
columnName = "activeSubId",
- initialValue = INVALID_SUBSCRIPTION_ID,
+ initialValue = null,
)
.stateIn(scope, started = SharingStarted.WhileSubscribed(), null)
@@ -264,22 +264,31 @@ constructor(
}
.stateIn(scope, SharingStarted.WhileSubscribed(), null)
- override val defaultDataSubId: StateFlow<Int> =
+ override val defaultDataSubId: StateFlow<Int?> =
broadcastDispatcher
.broadcastFlow(
IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
) { intent, _ ->
- intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, INVALID_SUBSCRIPTION_ID)
+ val subId =
+ intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, INVALID_SUBSCRIPTION_ID)
+ if (subId == INVALID_SUBSCRIPTION_ID) {
+ null
+ } else {
+ subId
+ }
}
.distinctUntilChanged()
.logDiffsForTable(
tableLogger,
LOGGING_PREFIX,
columnName = "defaultSubId",
- initialValue = INVALID_SUBSCRIPTION_ID,
+ initialValue = null,
)
- .onStart { emit(subscriptionManagerProxy.getDefaultDataSubscriptionId()) }
- .stateIn(scope, SharingStarted.WhileSubscribed(), INVALID_SUBSCRIPTION_ID)
+ .onStart {
+ val subId = subscriptionManagerProxy.getDefaultDataSubscriptionId()
+ emit(if (subId == INVALID_SUBSCRIPTION_ID) null else subId)
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), null)
private val carrierConfigChangedEvent =
broadcastDispatcher
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index 78731faa6167..be56461a96ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -72,7 +72,7 @@ interface MobileIconsInteractor {
val filteredSubscriptions: Flow<List<SubscriptionModel>>
/** Subscription ID of the current default data subscription */
- val defaultDataSubId: Flow<Int>
+ val defaultDataSubId: Flow<Int?>
/**
* The current list of [MobileIconInteractor]s associated with the current list of
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
index 71e19188f309..b1cc208e9b43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
@@ -32,6 +32,7 @@ import androidx.compose.ui.draw.alpha
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.compose.ui.viewinterop.AndroidView
+import androidx.core.view.isVisible
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.compose.theme.PlatformTheme
@@ -39,6 +40,7 @@ import com.android.keyguard.AlphaOptimizedLinearLayout
import com.android.systemui.plugins.DarkIconDispatcher
import com.android.systemui.res.R
import com.android.systemui.statusbar.chips.ui.compose.OngoingActivityChips
+import com.android.systemui.statusbar.core.StatusBarRootModernization
import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore
import com.android.systemui.statusbar.events.domain.interactor.SystemStatusEventAnimationInteractor
import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips
@@ -142,10 +144,14 @@ fun StatusBarRoot(
Box(Modifier.fillMaxSize()) {
// TODO(b/364360986): remove this before rolling the flag forward
- Disambiguation(viewModel = statusBarViewModel)
+ if (StatusBarRootModernization.SHOW_DISAMBIGUATION) {
+ Disambiguation(viewModel = statusBarViewModel)
+ }
Row(Modifier.fillMaxSize()) {
val scope = rememberCoroutineScope()
+ val visible =
+ statusBarViewModel.shouldHomeStatusBarBeVisible.collectAsStateWithLifecycle(false)
AndroidView(
factory = { context ->
val inflater = LayoutInflater.from(context)
@@ -280,7 +286,12 @@ fun StatusBarRoot(
}
onViewCreated(phoneStatusBarView)
phoneStatusBarView
- }
+ },
+ update = { view ->
+ // Show or hide the entire status bar. This is important so that we aren't
+ // visible when first inflated
+ view.isVisible = visible.value
+ },
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
index d9d9a29ee2b6..dcd2dbf57b42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
@@ -43,6 +43,7 @@ import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationSt
import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.Idle
import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel
import com.android.systemui.statusbar.featurepods.popups.ui.viewmodel.StatusBarPopupChipsViewModel
+import com.android.systemui.statusbar.headsup.shared.StatusBarNoHunBehavior
import com.android.systemui.statusbar.layout.ui.viewmodel.StatusBarContentInsetsViewModelStore
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor
@@ -80,6 +81,9 @@ import kotlinx.coroutines.flow.stateIn
* so that it's all in one place and easily testable outside of the fragment.
*/
interface HomeStatusBarViewModel {
+ /** Should the entire status bar be hidden? */
+ val shouldHomeStatusBarBeVisible: Flow<Boolean>
+
/**
* True if the device is currently transitioning from lockscreen to occluded and false
* otherwise.
@@ -271,10 +275,12 @@ constructor(
isHomeScreenStatusBarAllowedLegacy
}
- private val shouldHomeStatusBarBeVisible =
- combine(isHomeStatusBarAllowed, keyguardInteractor.isSecureCameraActive) {
+ override val shouldHomeStatusBarBeVisible =
+ combine(
isHomeStatusBarAllowed,
- isSecureCameraActive ->
+ keyguardInteractor.isSecureCameraActive,
+ headsUpNotificationInteractor.statusBarHeadsUpStatus,
+ ) { isHomeStatusBarAllowed, isSecureCameraActive, headsUpState ->
// When launching the camera over the lockscreen, the status icons would typically
// become visible momentarily before animating out, since we're not yet aware that the
// launching camera activity is fullscreen. Even once the activity finishes launching,
@@ -282,7 +288,7 @@ constructor(
// tells us to hide them.
// To ensure that this high-visibility animation is smooth, keep the icons hidden during
// a camera launch. See b/257292822.
- isHomeStatusBarAllowed && !isSecureCameraActive
+ headsUpState.isPinned || (isHomeStatusBarAllowed && !isSecureCameraActive)
}
private val isAnyChipVisible =
@@ -292,17 +298,32 @@ constructor(
primaryOngoingActivityChip.map { it is OngoingActivityChipModel.Shown }
}
+ /**
+ * True if we need to hide the usual start side content in order to show the heads up
+ * notification info.
+ */
+ private val hideStartSideContentForHeadsUp: Flow<Boolean> =
+ if (StatusBarNoHunBehavior.isEnabled) {
+ flowOf(false)
+ } else {
+ headsUpNotificationInteractor.statusBarHeadsUpStatus.map {
+ it == PinnedStatus.PinnedBySystem
+ }
+ }
+
override val shouldShowOperatorNameView: Flow<Boolean> =
combine(
shouldHomeStatusBarBeVisible,
- headsUpNotificationInteractor.statusBarHeadsUpStatus,
+ hideStartSideContentForHeadsUp,
homeStatusBarInteractor.visibilityViaDisableFlags,
homeStatusBarInteractor.shouldShowOperatorName,
- ) { shouldStatusBarBeVisible, headsUpStatus, visibilityViaDisableFlags, shouldShowOperator
- ->
- val hideForHeadsUp = headsUpStatus == PinnedStatus.PinnedBySystem
+ ) {
+ shouldStatusBarBeVisible,
+ hideStartSideContentForHeadsUp,
+ visibilityViaDisableFlags,
+ shouldShowOperator ->
shouldStatusBarBeVisible &&
- !hideForHeadsUp &&
+ !hideStartSideContentForHeadsUp &&
visibilityViaDisableFlags.isSystemInfoAllowed &&
shouldShowOperator
}
@@ -310,14 +331,13 @@ constructor(
override val isClockVisible: Flow<VisibilityModel> =
combine(
shouldHomeStatusBarBeVisible,
- headsUpNotificationInteractor.statusBarHeadsUpStatus,
+ hideStartSideContentForHeadsUp,
homeStatusBarInteractor.visibilityViaDisableFlags,
- ) { shouldStatusBarBeVisible, headsUpStatus, visibilityViaDisableFlags ->
- val hideClockForHeadsUp = headsUpStatus == PinnedStatus.PinnedBySystem
+ ) { shouldStatusBarBeVisible, hideStartSideContentForHeadsUp, visibilityViaDisableFlags ->
val showClock =
shouldStatusBarBeVisible &&
visibilityViaDisableFlags.isClockAllowed &&
- !hideClockForHeadsUp
+ !hideStartSideContentForHeadsUp
// Always use View.INVISIBLE here, so that animations work
VisibilityModel(showClock.toVisibleOrInvisible(), visibilityViaDisableFlags.animate)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/StatusBarOperatorNameViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/StatusBarOperatorNameViewModel.kt
index 7ae74c3bfb65..0b83c4e3dea3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/StatusBarOperatorNameViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/StatusBarOperatorNameViewModel.kt
@@ -22,6 +22,7 @@ import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
/**
* View model for the operator name (aka carrier name) of the carrier for the default data
@@ -34,6 +35,10 @@ class StatusBarOperatorNameViewModel
constructor(mobileIconsInteractor: MobileIconsInteractor) {
val operatorName: Flow<String?> =
mobileIconsInteractor.defaultDataSubId.flatMapLatest {
- mobileIconsInteractor.getMobileConnectionInteractorForSubId(it).carrierName
+ if (it == null) {
+ flowOf(null)
+ } else {
+ mobileIconsInteractor.getMobileConnectionInteractorForSubId(it).carrierName
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
index cb26679434ef..520c5632370b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
@@ -408,6 +408,11 @@ constructor(
action.extras.getBoolean(Notification.Action.EXTRA_IS_MAGIC, false)
) {
background = MagicActionBackgroundDrawable(parent.context)
+ val textColor =
+ parent.context.getColor(
+ com.android.internal.R.color.materialColorOnPrimaryContainer
+ )
+ setTextColor(textColor)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt
index fdc2d8d96f9b..5fa15b831299 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt
@@ -43,6 +43,7 @@ import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
@@ -123,12 +124,20 @@ constructor(
* explicitly wants a shortcut to DND). Please prefer using [modes] or [activeModes] in all
* other scenarios.
*/
- val dndMode: StateFlow<ZenMode?> by lazy {
- ModesUi.assertInNewMode()
- zenModeRepository.modes
- .map { modes -> modes.singleOrNull { it.isManualDnd } }
- .stateIn(scope = backgroundScope, started = SharingStarted.Eagerly, initialValue = null)
- }
+ val dndMode: StateFlow<ZenMode?> =
+ if (ModesUi.isEnabled)
+ zenModeRepository.modes
+ .map { modes -> modes.singleOrNull { it.isManualDnd } }
+ .stateIn(
+ scope = backgroundScope,
+ started = SharingStarted.Eagerly,
+ initialValue = null,
+ )
+ else MutableStateFlow<ZenMode?>(null)
+ get() {
+ ModesUi.assertInNewMode()
+ return field
+ }
/** Flow returning the currently active mode(s), if any. */
val activeModes: Flow<ActiveZenModes> =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt
index a98a9e0c16d2..12ef68dafa64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt
@@ -24,6 +24,7 @@ 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.statusbar.domain.interactor.KeyguardStatusBarInteractor
+import com.android.systemui.statusbar.headsup.shared.StatusBarNoHunBehavior
import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback
@@ -59,7 +60,7 @@ constructor(
) {
private val showingHeadsUpStatusBar: Flow<Boolean> =
- if (SceneContainerFlag.isEnabled) {
+ if (SceneContainerFlag.isEnabled && !StatusBarNoHunBehavior.isEnabled) {
headsUpNotificationInteractor.statusBarHeadsUpStatus.map { it.isPinned }
} else {
flowOf(false)
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt
index 284e23e5a288..47c82e309d9b 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt
@@ -26,7 +26,10 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInteropFilter
@@ -48,8 +51,13 @@ fun GestureTutorialScreen(
onBack: () -> Unit,
) {
BackHandler(onBack = onBack)
+ var cachedTutorialState: TutorialActionState by
+ rememberSaveable(stateSaver = TutorialActionState.stateSaver()) {
+ mutableStateOf(NotStarted)
+ }
val easterEggTriggered by easterEggTriggeredFlow.collectAsStateWithLifecycle(false)
- val tutorialState by tutorialStateFlow.collectAsStateWithLifecycle(NotStarted)
+ val tutorialState by tutorialStateFlow.collectAsStateWithLifecycle(cachedTutorialState)
+ cachedTutorialState = tutorialState
TouchpadGesturesHandlingBox(
motionEventConsumer,
tutorialState,
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
index 66a900bd72d8..c8a58400069e 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
@@ -218,9 +218,11 @@ private fun TutorialButton(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
+ // contentDescription is set to null because the icon is decorative and we don't want to
+ // repeat the text twice
Icon(
imageVector = icon,
- contentDescription = text,
+ contentDescription = null,
modifier = Modifier.width(30.dp).height(30.dp),
tint = iconColor,
)
diff --git a/packages/SystemUI/src/com/android/systemui/util/DelayableMarqueeTextView.kt b/packages/SystemUI/src/com/android/systemui/util/DelayableMarqueeTextView.kt
index ef9340a332dc..ffaddfbb9b15 100644
--- a/packages/SystemUI/src/com/android/systemui/util/DelayableMarqueeTextView.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/DelayableMarqueeTextView.kt
@@ -20,11 +20,13 @@ import android.content.Context
import android.util.AttributeSet
import com.android.systemui.res.R
-class DelayableMarqueeTextView @JvmOverloads constructor(
+open class DelayableMarqueeTextView
+@JvmOverloads
+constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
- defStyleRes: Int = 0
+ defStyleRes: Int = 0,
) : SafeMarqueeTextView(context, attrs, defStyleAttr, defStyleRes) {
var marqueeDelay: Long = DEFAULT_MARQUEE_DELAY
@@ -39,16 +41,20 @@ class DelayableMarqueeTextView @JvmOverloads constructor(
}
init {
- val typedArray = context.theme.obtainStyledAttributes(
+ val typedArray =
+ context.theme.obtainStyledAttributes(
attrs,
R.styleable.DelayableMarqueeTextView,
defStyleAttr,
- defStyleRes
- )
- marqueeDelay = typedArray.getInteger(
- R.styleable.DelayableMarqueeTextView_marqueeDelay,
- DEFAULT_MARQUEE_DELAY.toInt()
- ).toLong()
+ defStyleRes,
+ )
+ marqueeDelay =
+ typedArray
+ .getInteger(
+ R.styleable.DelayableMarqueeTextView_marqueeDelay,
+ DEFAULT_MARQUEE_DELAY.toInt(),
+ )
+ .toLong()
typedArray.recycle()
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt
index 96630ca36b97..908249dbca08 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt
@@ -144,7 +144,6 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) {
ringerState.orientation,
)
}
-
is RingerDrawerState.Closed -> {
if (
uiModel.selectedButton.ringerMode ==
@@ -189,7 +188,6 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) {
}
}
}
-
is RingerDrawerState.Open -> {
drawerContainer.animateAndBindDrawerButtons(
viewModel,
@@ -220,7 +218,6 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) {
}
}
}
-
is RingerViewModelState.Unavailable -> {
drawerContainer.visibility = View.GONE
volumeDialogBackgroundView.setBackgroundResource(
@@ -251,7 +248,7 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) {
.requireViewById<ImageButton>(R.id.volume_drawer_button)
val previousIndex =
uiModel.availableButtons.indexOfFirst {
- it?.ringerMode == uiModel.drawerState.previousMode
+ it.ringerMode == uiModel.drawerState.previousMode
}
val unselectedButton =
getChildAt(count - previousIndex)
@@ -306,20 +303,18 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) {
) {
val count = uiModel.availableButtons.size
uiModel.availableButtons.fastForEachIndexed { index, ringerButton ->
- ringerButton?.let {
- val view = getChildAt(count - index)
- val isOpen = uiModel.drawerState is RingerDrawerState.Open
- if (index == uiModel.currentButtonIndex) {
- view.bindDrawerButton(
- if (isOpen) it else uiModel.selectedButton,
- viewModel,
- isOpen,
- isSelected = true,
- isAnimated = isAnimated,
- )
- } else {
- view.bindDrawerButton(it, viewModel, isOpen, isAnimated = isAnimated)
- }
+ val view = getChildAt(count - index)
+ val isOpen = uiModel.drawerState is RingerDrawerState.Open
+ if (index == uiModel.currentButtonIndex) {
+ view.bindDrawerButton(
+ if (isOpen) ringerButton else uiModel.selectedButton,
+ viewModel,
+ isOpen,
+ isSelected = true,
+ isAnimated = isAnimated,
+ )
+ } else {
+ view.bindDrawerButton(ringerButton, viewModel, isOpen, isAnimated = isAnimated)
}
}
onAnimationEnd?.run()
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/RingerViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/RingerViewModel.kt
index 96d4f62416bf..8613610ad1bf 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/RingerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/RingerViewModel.kt
@@ -19,7 +19,7 @@ package com.android.systemui.volume.dialog.ringer.ui.viewmodel
/** Models volume dialog ringer */
data class RingerViewModel(
/** List of the available buttons according to the available modes */
- val availableButtons: List<RingerButtonViewModel?>,
+ val availableButtons: List<RingerButtonViewModel>,
/** The index of the currently selected button */
val currentButtonIndex: Int,
/** Currently selected button. */
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt
index eec64d9a2f86..b0d6d62289c7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt
@@ -35,6 +35,7 @@ import com.android.systemui.res.R
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.onConfigChanged
+import com.android.systemui.util.time.SystemClock
import com.android.systemui.volume.Events
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
@@ -50,10 +51,13 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
+private const val DRAWER_STATE_ANIMATION_DURATION = 400L
private const val SHOW_RINGER_TOAST_COUNT = 12
@VolumeDialogScope
@@ -69,6 +73,7 @@ constructor(
private val volumeDialogLogger: VolumeDialogLogger,
private val visibilityInteractor: VolumeDialogVisibilityInteractor,
configurationController: ConfigurationController,
+ private val systemClock: SystemClock,
) {
private val drawerState = MutableStateFlow<RingerDrawerState>(RingerDrawerState.Initial)
@@ -106,9 +111,29 @@ constructor(
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.build()
+ private var lastClickTime = 0L
+ init {
+ ringerViewModel
+ .onEach { viewModelState ->
+ when (viewModelState) {
+ is RingerViewModelState.Available ->
+ volumeDialogLogger.onRingerDrawerAvailable(
+ viewModelState.uiModel.availableButtons.map { it.ringerMode }
+ )
+ is RingerViewModelState.Unavailable ->
+ volumeDialogLogger.onRingerDrawerUnavailable()
+ }
+ }
+ .launchIn(coroutineScope)
+ }
+
fun onRingerButtonClicked(ringerMode: RingerMode, isSelectedButton: Boolean = false) {
+ val currentTime = systemClock.currentTimeMillis()
+ if (currentTime - lastClickTime < DRAWER_STATE_ANIMATION_DURATION) return
+ lastClickTime = currentTime
if (drawerState.value is RingerDrawerState.Open && !isSelectedButton) {
Events.writeEvent(Events.EVENT_RINGER_TOGGLE, ringerMode.value)
+ volumeDialogLogger.onRingerModeChanged(ringerMode)
provideTouchFeedback(ringerMode)
maybeShowToast(ringerMode)
ringerInteractor.setRingerMode(ringerMode)
@@ -159,7 +184,9 @@ constructor(
RingerViewModelState.Available(
RingerViewModel(
availableButtons =
- availableModes.map { mode -> toButtonViewModel(mode, isZenMuted) },
+ availableModes.mapNotNull { mode ->
+ toButtonViewModel(mode, isZenMuted)
+ },
currentButtonIndex = currentIndex,
selectedButton = it,
drawerState = drawerState,
@@ -219,7 +246,6 @@ constructor(
hintLabelResId = R.string.volume_ringer_hint_unmute,
ringerMode = ringerMode,
)
-
availableModes.contains(RingerMode(RINGER_MODE_VIBRATE)) ->
RingerButtonViewModel(
imageResId = R.drawable.ic_speaker_on,
@@ -232,7 +258,6 @@ constructor(
hintLabelResId = R.string.volume_ringer_hint_vibrate,
ringerMode = ringerMode,
)
-
else ->
RingerButtonViewModel(
imageResId = R.drawable.ic_speaker_on,
@@ -269,17 +294,14 @@ constructor(
null
}
}
-
RINGER_MODE_SILENT ->
applicationContext.getString(
internalR.string.volume_dialog_ringer_guidance_silent
)
-
RINGER_MODE_VIBRATE ->
applicationContext.getString(
internalR.string.volume_dialog_ringer_guidance_vibrate
)
-
else ->
applicationContext.getString(
internalR.string.volume_dialog_ringer_guidance_vibrate
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/shared/VolumeDialogLogger.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/shared/VolumeDialogLogger.kt
index 9a3aa7e3d79f..cccf090fae85 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/shared/VolumeDialogLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/shared/VolumeDialogLogger.kt
@@ -45,6 +45,52 @@ class VolumeDialogLogger @Inject constructor(@VolumeLog private val logBuffer: L
)
}
+ fun onVolumeSliderAdjustmentFinished(volume: Int, stream: Int) {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ int1 = volume
+ int2 = stream
+ },
+ { "Volume adjusted: volume=$int1 stream=$int2" },
+ )
+ }
+
+ fun onVolumeSlidersUpdated(primaryStream: Int, floating: Collection<Int>) {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ int1 = primaryStream
+ str1 = floating.joinToString(",") { it.toString() }
+ },
+ { "Showing streams: primary=$int1 floating=$str1" },
+ )
+ }
+
+ fun onRingerModeChanged(ringerMode: RingerMode) {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { int1 = ringerMode.value },
+ { "Ringer mode changed to: $int1" },
+ )
+ }
+
+ fun onRingerDrawerAvailable(modes: List<RingerMode>) {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { str1 = modes.joinToString(",") { it.value.toString() } },
+ { "Ringer drawer available with modes: $str1" },
+ )
+ }
+
+ fun onRingerDrawerUnavailable() {
+ logBuffer.log(TAG, LogLevel.DEBUG, {}, { "Ringer drawer unavailable" })
+ }
+
fun onCurrentRingerModeIsUnsupported(ringerMode: RingerMode) {
logBuffer.log(
TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt
index 3b964fdec1b8..d40302408dd6 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt
@@ -27,6 +27,7 @@ import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSlide
import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSliderStateModel
import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSliderViewModel
import com.google.android.material.slider.Slider
+import com.google.android.material.slider.Slider.OnSliderTouchListener
import javax.inject.Inject
import kotlin.math.roundToInt
import kotlinx.coroutines.CoroutineScope
@@ -68,6 +69,15 @@ constructor(
sliderView.addOnChangeListener { _, value, fromUser ->
viewModel.setStreamVolume(value.roundToInt(), fromUser)
}
+ sliderView.addOnSliderTouchListener(
+ object : OnSliderTouchListener {
+ override fun onStartTrackingTouch(slider: Slider) {}
+
+ override fun onStopTrackingTouch(slider: Slider) {
+ viewModel.onStreamChangeFinished(slider.value.roundToInt())
+ }
+ }
+ )
viewModel.isDisabledByZenMode.onEach { sliderView.isEnabled = !it }.launchIn(this)
viewModel.state
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderIconProvider.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderIconProvider.kt
index 71fe22ba4b01..9cf02f26c9f7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderIconProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderIconProvider.kt
@@ -82,10 +82,6 @@ constructor(
ringerMode: RingerMode?,
): Int {
val isStreamOffline = level == 0 || isMuted
- when (ringerMode?.value) {
- AudioManager.RINGER_MODE_VIBRATE -> return R.drawable.ic_volume_ringer_vibrate
- AudioManager.RINGER_MODE_SILENT -> return R.drawable.ic_ring_volume_off
- }
if (isRoutedToBluetooth) {
return if (stream == AudioManager.STREAM_VOICE_CALL) {
R.drawable.ic_volume_bt_sco
@@ -98,29 +94,39 @@ constructor(
}
}
+ val isLevelLow = level < (levelMax + levelMin) / 2
return if (isStreamOffline) {
+ val ringerOfflineIcon =
+ when (ringerMode?.value) {
+ AudioManager.RINGER_MODE_VIBRATE -> return R.drawable.ic_volume_ringer_vibrate
+ AudioManager.RINGER_MODE_SILENT -> return R.drawable.ic_ring_volume_off
+ else -> null
+ }
when (stream) {
AudioManager.STREAM_MUSIC -> R.drawable.ic_volume_media_mute
- AudioManager.STREAM_NOTIFICATION -> R.drawable.ic_volume_ringer_mute
+ AudioManager.STREAM_NOTIFICATION ->
+ ringerOfflineIcon ?: R.drawable.ic_volume_ringer_mute
+ AudioManager.STREAM_RING -> ringerOfflineIcon ?: R.drawable.ic_volume_ringer_vibrate
AudioManager.STREAM_ALARM -> R.drawable.ic_volume_alarm_mute
AudioManager.STREAM_SYSTEM -> R.drawable.ic_volume_system_mute
else -> null
- } ?: getIconForStream(stream)
- } else {
- if (level < (levelMax + levelMin) / 2) {
- // This icon is different on TV
- R.drawable.ic_volume_media_low
- } else {
- getIconForStream(stream)
}
- }
+ } else {
+ null
+ } ?: getIconForStream(stream = stream, isLevelLow = isLevelLow)
}
@DrawableRes
- private fun getIconForStream(stream: Int): Int {
+ private fun getIconForStream(stream: Int, isLevelLow: Boolean): Int {
return when (stream) {
AudioManager.STREAM_ACCESSIBILITY -> R.drawable.ic_volume_accessibility
- AudioManager.STREAM_MUSIC -> R.drawable.ic_volume_media
+ AudioManager.STREAM_MUSIC ->
+ if (isLevelLow) {
+ // This icon is different on TV
+ R.drawable.ic_volume_media_low
+ } else {
+ R.drawable.ic_volume_media
+ }
AudioManager.STREAM_RING -> R.drawable.ic_ring_volume
AudioManager.STREAM_NOTIFICATION -> R.drawable.ic_volume_ringer
AudioManager.STREAM_ALARM -> R.drawable.ic_alarm
@@ -135,7 +141,9 @@ constructor(
* affect the [stream]
*/
private fun ringerModeForStream(stream: Int): Flow<RingerMode?> {
- return if (stream == AudioManager.STREAM_RING) {
+ return if (
+ stream == AudioManager.STREAM_RING || stream == AudioManager.STREAM_NOTIFICATION
+ ) {
audioVolumeInteractor.ringerMode
} else {
flowOf(null)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt
index d999910675b0..89dd0352afa7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt
@@ -20,9 +20,11 @@ import com.android.systemui.util.time.SystemClock
import com.android.systemui.volume.Events
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
+import com.android.systemui.volume.dialog.shared.VolumeDialogLogger
import com.android.systemui.volume.dialog.shared.model.VolumeDialogStreamModel
import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope
import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSliderInteractor
+import com.android.systemui.volume.dialog.sliders.domain.model.VolumeDialogSliderType
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -60,6 +62,8 @@ constructor(
@VolumeDialog private val coroutineScope: CoroutineScope,
private val volumeDialogSliderIconProvider: VolumeDialogSliderIconProvider,
private val systemClock: SystemClock,
+ private val sliderType: VolumeDialogSliderType,
+ private val logger: VolumeDialogLogger,
) {
private val userVolumeUpdates = MutableStateFlow<VolumeUpdate?>(null)
@@ -110,6 +114,10 @@ constructor(
}
}
+ fun onStreamChangeFinished(volume: Int) {
+ logger.onVolumeSliderAdjustmentFinished(volume = volume, stream = sliderType.audioStream)
+ }
+
private fun getTimestampMillis(): Long = systemClock.uptimeMillis()
private data class VolumeUpdate(val newVolumeLevel: Int, val timestampMillis: Long)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModel.kt
index d8e6aec026c6..344dadcce229 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModel.kt
@@ -18,6 +18,7 @@ package com.android.systemui.volume.dialog.sliders.ui.viewmodel
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
+import com.android.systemui.volume.dialog.shared.VolumeDialogLogger
import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderComponent
import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSlidersInteractor
import javax.inject.Inject
@@ -33,13 +34,18 @@ class VolumeDialogSlidersViewModel
@Inject
constructor(
@VolumeDialog coroutineScope: CoroutineScope,
- private val slidersInteractor: VolumeDialogSlidersInteractor,
+ slidersInteractor: VolumeDialogSlidersInteractor,
private val sliderComponentFactory: VolumeDialogSliderComponent.Factory,
+ private val volumeDialogLogger: VolumeDialogLogger,
) {
val sliders: Flow<VolumeDialogSliderUiModel> =
slidersInteractor.sliders
.map { slidersModel ->
+ volumeDialogLogger.onVolumeSlidersUpdated(
+ slidersModel.slider.audioStream,
+ slidersModel.floatingSliders.map { it.audioStream },
+ )
VolumeDialogSliderUiModel(
sliderComponent = sliderComponentFactory.create(slidersModel.slider),
floatingSliderComponent =
diff --git a/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioSharingInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioSharingInteractor.kt
index 7da041e7ef19..411288ff1274 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioSharingInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioSharingInteractor.kt
@@ -22,6 +22,7 @@ import android.media.AudioManager.STREAM_MUSIC
import androidx.annotation.IntRange
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.settingslib.bluetooth.BluetoothUtils
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.flags.Flags
import com.android.settingslib.volume.data.repository.AudioSharingRepository
import com.android.settingslib.volume.data.repository.AudioSharingRepository.Companion.AUDIO_SHARING_VOLUME_MAX
@@ -42,12 +43,19 @@ import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
interface AudioSharingInteractor {
/** Audio sharing state on the device. */
val isInAudioSharing: Flow<Boolean>
+ /** Primary audio sharing device. */
+ val primaryDevice: Flow<CachedBluetoothDevice?>
+
+ /** Secondary audio sharing device. */
+ val secondaryDevice: Flow<CachedBluetoothDevice?>
+
/** Audio sharing secondary headset volume changes. */
val volume: Flow<Int?>
@@ -86,6 +94,11 @@ constructor(
private val audioSharingRepository: AudioSharingRepository,
) : AudioSharingInteractor {
override val isInAudioSharing: Flow<Boolean> = audioSharingRepository.inAudioSharing
+ override val primaryDevice: Flow<CachedBluetoothDevice?>
+ get() = audioSharingRepository.primaryDevice
+
+ override val secondaryDevice: Flow<CachedBluetoothDevice?>
+ get() = audioSharingRepository.secondaryDevice
override val volume: Flow<Int?> =
combine(audioSharingRepository.secondaryGroupId, audioSharingRepository.volumeMap) {
@@ -148,6 +161,8 @@ constructor(
@SysUISingleton
class AudioSharingInteractorEmptyImpl @Inject constructor() : AudioSharingInteractor {
override val isInAudioSharing: Flow<Boolean> = flowOf(false)
+ override val primaryDevice: Flow<CachedBluetoothDevice?> = flowOf(null)
+ override val secondaryDevice: Flow<CachedBluetoothDevice?> = flowOf(null)
override val volume: Flow<Int?> = emptyFlow()
override val volumeMin: Int = EMPTY_VOLUME
override val volumeMax: Int = EMPTY_VOLUME
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractor.kt
index 1e4afc0ac5fe..a326da45a7fc 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractor.kt
@@ -21,6 +21,7 @@ import com.android.settingslib.volume.data.repository.AudioSystemRepository
import com.android.settingslib.volume.domain.interactor.AudioModeInteractor
import com.android.settingslib.volume.shared.model.AudioStream
import com.android.systemui.Flags
+import com.android.systemui.volume.domain.interactor.AudioSharingInteractor
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession
import com.android.systemui.volume.panel.component.mediaoutput.shared.model.isTheSameSession
@@ -44,6 +45,7 @@ constructor(
mediaOutputInteractor: MediaOutputInteractor,
audioModeInteractor: AudioModeInteractor,
private val audioSystemRepository: AudioSystemRepository,
+ audioSharingInteractor: AudioSharingInteractor,
) {
val volumePanelSliders: StateFlow<List<SliderType>> =
@@ -51,7 +53,8 @@ constructor(
mediaOutputInteractor.activeMediaDeviceSessions,
mediaOutputInteractor.defaultActiveMediaSession.filterData(),
audioModeInteractor.isOngoingCall,
- ) { activeSessions, defaultSession, isOngoingCall ->
+ audioSharingInteractor.volume,
+ ) { activeSessions, defaultSession, isOngoingCall, audioSharingVolume ->
coroutineScope {
val viewModels = buildList {
if (isOngoingCall) {
@@ -61,8 +64,14 @@ constructor(
if (defaultSession?.isTheSameSession(activeSessions.remote) == true) {
addSession(activeSessions.remote)
addStream(AudioManager.STREAM_MUSIC)
+ if (Flags.showAudioSharingSliderInVolumePanel()) {
+ audioSharingVolume?.let { addAudioSharingStream() }
+ }
} else {
addStream(AudioManager.STREAM_MUSIC)
+ if (Flags.showAudioSharingSliderInVolumePanel()) {
+ audioSharingVolume?.let { addAudioSharingStream() }
+ }
addSession(activeSessions.remote)
}
@@ -89,13 +98,18 @@ constructor(
// Hide other streams except STREAM_MUSIC if the isSingleVolume mode is on. This makes sure
// the volume slider in volume panel is consistent with the volume slider inside system
// settings app.
- if (Flags.onlyShowMediaStreamSliderInSingleVolumeMode() &&
- audioSystemRepository.isSingleVolume &&
- stream != AudioManager.STREAM_MUSIC
+ if (
+ Flags.onlyShowMediaStreamSliderInSingleVolumeMode() &&
+ audioSystemRepository.isSingleVolume &&
+ stream != AudioManager.STREAM_MUSIC
) {
return
}
add(SliderType.Stream(AudioStream(stream)))
}
+
+ private fun MutableList<SliderType>.addAudioSharingStream() {
+ add(SliderType.AudioSharingStream)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/model/SliderType.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/model/SliderType.kt
index 6129ce543e2e..f180744eac22 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/model/SliderType.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/model/SliderType.kt
@@ -27,4 +27,7 @@ sealed interface SliderType {
/** The represents media device casting volume. */
data class MediaDeviceCast(val session: MediaDeviceSession) : SliderType
+
+ /** Represents the audio sharing volume stream. */
+ data object AudioSharingStream : SliderType
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModel.kt
new file mode 100644
index 000000000000..4ce9fe561aed
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModel.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel
+
+import android.content.Context
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.Flags
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
+import com.android.systemui.res.R
+import com.android.systemui.volume.domain.interactor.AudioSharingInteractor
+import com.android.systemui.volume.panel.ui.VolumePanelUiEvent
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlin.math.roundToInt
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
+
+@OptIn(ExperimentalCoroutinesApi::class)
+class AudioSharingStreamSliderViewModel
+@AssistedInject
+constructor(
+ @Assisted private val coroutineScope: CoroutineScope,
+ private val context: Context,
+ private val audioSharingInteractor: AudioSharingInteractor,
+ private val uiEventLogger: UiEventLogger,
+ private val hapticsViewModelFactory: SliderHapticsViewModel.Factory,
+) : SliderViewModel {
+ private val volumeChanges = MutableStateFlow<Int?>(null)
+
+ override val slider: StateFlow<SliderState> =
+ combine(audioSharingInteractor.volume, audioSharingInteractor.secondaryDevice) {
+ volume,
+ device ->
+ val deviceName = device?.name ?: return@combine SliderState.Empty
+ if (volume == null) {
+ SliderState.Empty
+ } else {
+ State(
+ value = volume.toFloat(),
+ valueRange =
+ audioSharingInteractor.volumeMin.toFloat()..audioSharingInteractor
+ .volumeMax
+ .toFloat(),
+ icon = Icon.Resource(R.drawable.ic_volume_media_bt, null),
+ label = deviceName,
+ )
+ }
+ }
+ .stateIn(coroutineScope, SharingStarted.Eagerly, SliderState.Empty)
+
+ init {
+ volumeChanges
+ .filterNotNull()
+ .onEach { audioSharingInteractor.setStreamVolume(it) }
+ .launchIn(coroutineScope)
+ }
+
+ override fun onValueChanged(state: SliderState, newValue: Float) {
+ val audioViewModel = state as? State
+ audioViewModel ?: return
+ volumeChanges.tryEmit(newValue.roundToInt())
+ }
+
+ override fun onValueChangeFinished() {
+ uiEventLogger.log(VolumePanelUiEvent.VOLUME_PANEL_AUDIO_SHARING_SLIDER_TOUCHED)
+ }
+
+ override fun toggleMuted(state: SliderState) {}
+
+ override fun getSliderHapticsViewModelFactory(): SliderHapticsViewModel.Factory? =
+ if (Flags.hapticsForComposeSliders() && slider.value != SliderState.Empty) {
+ hapticsViewModelFactory
+ } else {
+ null
+ }
+
+ private data class State(
+ override val value: Float,
+ override val valueRange: ClosedFloatingPointRange<Float>,
+ override val icon: Icon,
+ override val label: String,
+ ) : SliderState {
+ override val isEnabled: Boolean
+ get() = true
+
+ override val a11yStep: Int
+ get() = 1
+
+ override val disabledMessage: String?
+ get() = null
+
+ override val isMutable: Boolean
+ get() = false
+
+ override val a11yClickDescription: String?
+ get() = null
+
+ override val a11yStateDescription: String?
+ get() = null
+ }
+
+ @AssistedFactory
+ interface Factory {
+ fun create(coroutineScope: CoroutineScope): AudioSharingStreamSliderViewModel
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
index 5b8d9b045475..4410cb156723 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
@@ -21,6 +21,7 @@ import android.media.AudioManager
import android.util.Log
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.internal.logging.UiEventLogger
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.volume.domain.interactor.AudioVolumeInteractor
import com.android.settingslib.volume.shared.model.AudioStream
import com.android.settingslib.volume.shared.model.AudioStreamModel
@@ -31,6 +32,8 @@ import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
import com.android.systemui.modes.shared.ModesUiIcons
import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor
+import com.android.systemui.util.kotlin.combine
+import com.android.systemui.volume.domain.interactor.AudioSharingInteractor
import com.android.systemui.volume.panel.shared.VolumePanelLogger
import com.android.systemui.volume.panel.ui.VolumePanelUiEvent
import dagger.assisted.Assisted
@@ -42,7 +45,6 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
@@ -59,23 +61,14 @@ constructor(
private val context: Context,
private val audioVolumeInteractor: AudioVolumeInteractor,
private val zenModeInteractor: ZenModeInteractor,
+ private val audioSharingInteractor: AudioSharingInteractor,
private val uiEventLogger: UiEventLogger,
private val volumePanelLogger: VolumePanelLogger,
private val hapticsViewModelFactory: SliderHapticsViewModel.Factory,
) : SliderViewModel {
private val volumeChanges = MutableStateFlow<Int?>(null)
- private val streamsAffectedByRing =
- setOf(AudioManager.STREAM_RING, AudioManager.STREAM_NOTIFICATION)
private val audioStream = audioStreamWrapper.audioStream
- private val iconsByStream =
- mapOf(
- AudioStream(AudioManager.STREAM_MUSIC) to R.drawable.ic_music_note,
- AudioStream(AudioManager.STREAM_VOICE_CALL) to R.drawable.ic_call,
- AudioStream(AudioManager.STREAM_RING) to R.drawable.ic_ring_volume,
- AudioStream(AudioManager.STREAM_NOTIFICATION) to R.drawable.ic_volume_ringer,
- AudioStream(AudioManager.STREAM_ALARM) to R.drawable.ic_volume_alarm,
- )
private val labelsByStream =
mapOf(
AudioStream(AudioManager.STREAM_MUSIC) to R.string.stream_music,
@@ -104,9 +97,18 @@ constructor(
audioVolumeInteractor.canChangeVolume(audioStream),
audioVolumeInteractor.ringerMode,
streamDisabledMessage(),
- ) { model, isEnabled, ringerMode, streamDisabledMessage ->
+ audioSharingInteractor.isInAudioSharing,
+ audioSharingInteractor.primaryDevice,
+ ) { model, isEnabled, ringerMode, streamDisabledMessage, isInAudioSharing, primaryDevice
+ ->
volumePanelLogger.onVolumeUpdateReceived(audioStream, model.volume)
- model.toState(isEnabled, ringerMode, streamDisabledMessage)
+ model.toState(
+ isEnabled,
+ ringerMode,
+ streamDisabledMessage,
+ isInAudioSharing,
+ primaryDevice,
+ )
}
.stateIn(coroutineScope, SharingStarted.Eagerly, SliderState.Empty)
@@ -149,14 +151,15 @@ constructor(
isEnabled: Boolean,
ringerMode: RingerMode,
disabledMessage: String?,
+ inAudioSharing: Boolean,
+ primaryDevice: CachedBluetoothDevice?,
): State {
- val label =
- labelsByStream[audioStream]?.let(context::getString)
- ?: error("No label for the stream: $audioStream")
+ val label = getLabel(inAudioSharing, primaryDevice)
+ val icon = getIcon(ringerMode, inAudioSharing)
return State(
value = volume.toFloat(),
valueRange = volumeRange.first.toFloat()..volumeRange.last.toFloat(),
- icon = getIcon(ringerMode),
+ icon = icon,
label = label,
disabledMessage = disabledMessage,
isEnabled = isEnabled,
@@ -175,9 +178,9 @@ constructor(
null
},
a11yStateDescription =
- if (volume == volumeRange.first) {
+ if (isMuted) {
context.getString(
- if (audioStream.value in streamsAffectedByRing) {
+ if (isAffectedByRingerMode) {
if (ringerMode.value == AudioManager.RINGER_MODE_VIBRATE) {
R.string.volume_panel_hint_vibrate
} else {
@@ -224,28 +227,61 @@ constructor(
}
}
- private fun AudioStreamModel.getIcon(ringerMode: RingerMode): Icon {
+ private fun AudioStreamModel.getLabel(
+ inAudioSharing: Boolean,
+ primaryDevice: CachedBluetoothDevice?,
+ ): String =
+ if (
+ Flags.showAudioSharingSliderInVolumePanel() &&
+ audioStream.value == AudioManager.STREAM_MUSIC &&
+ inAudioSharing
+ ) {
+ primaryDevice?.name ?: context.getString(R.string.stream_music)
+ } else {
+ labelsByStream[audioStream]?.let(context::getString)
+ ?: error("No label for the stream: $audioStream")
+ }
+
+ private fun AudioStreamModel.getIcon(ringerMode: RingerMode, inAudioSharing: Boolean): Icon {
val iconRes =
- if (isAffectedByMute && isMuted) {
- if (audioStream.value in streamsAffectedByRing) {
+ if (isMuted) {
+ if (isAffectedByRingerMode) {
if (ringerMode.value == AudioManager.RINGER_MODE_VIBRATE) {
R.drawable.ic_volume_ringer_vibrate
} else {
R.drawable.ic_volume_off
}
} else {
- R.drawable.ic_volume_off
+ if (
+ Flags.showAudioSharingSliderInVolumePanel() &&
+ audioStream.value == AudioManager.STREAM_MUSIC &&
+ inAudioSharing
+ ) {
+ R.drawable.ic_volume_media_bt_mute
+ } else R.drawable.ic_volume_off
}
} else {
- iconsByStream[audioStream]
- ?: run {
- Log.wtf(TAG, "No icon for the stream: $audioStream")
- R.drawable.ic_music_note
- }
+ getIconByStream(audioStream, inAudioSharing)
}
return Icon.Resource(iconRes, null)
}
+ private fun getIconByStream(audioStream: AudioStream, inAudioSharing: Boolean): Int =
+ when (audioStream.value) {
+ AudioManager.STREAM_MUSIC ->
+ if (Flags.showAudioSharingSliderInVolumePanel() && inAudioSharing) {
+ R.drawable.ic_volume_media_bt
+ } else R.drawable.ic_music_note
+ AudioManager.STREAM_VOICE_CALL -> R.drawable.ic_call
+ AudioManager.STREAM_RING -> R.drawable.ic_ring_volume
+ AudioManager.STREAM_NOTIFICATION -> R.drawable.ic_volume_ringer
+ AudioManager.STREAM_ALARM -> R.drawable.ic_volume_alarm
+ else -> {
+ Log.wtf(TAG, "No icon for the stream: $audioStream")
+ R.drawable.ic_music_note
+ }
+ }
+
private val AudioStreamModel.volumeRange: IntRange
get() = minVolume..maxVolume
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt
index 96afbc1feaaf..28f11050fa4a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt
@@ -16,6 +16,7 @@
package com.android.systemui.volume.panel.component.volume.ui.viewmodel
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.settingslib.volume.domain.interactor.AudioModeInteractor
import com.android.settingslib.volume.shared.model.AudioStream
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaDeviceSessionInteractor
@@ -23,6 +24,7 @@ import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor
import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession
import com.android.systemui.volume.panel.component.volume.domain.interactor.AudioSlidersInteractor
import com.android.systemui.volume.panel.component.volume.domain.model.SliderType
+import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.AudioSharingStreamSliderViewModel
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.AudioStreamSliderViewModel
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.CastVolumeSliderViewModel
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel
@@ -45,7 +47,6 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.transformLatest
-import com.android.app.tracing.coroutines.launchTraced as launch
/**
* Controls the behaviour of the whole audio
@@ -61,6 +62,7 @@ constructor(
mediaDeviceSessionInteractor: MediaDeviceSessionInteractor,
private val streamSliderViewModelFactory: AudioStreamSliderViewModel.Factory,
private val castVolumeSliderViewModelFactory: CastVolumeSliderViewModel.Factory,
+ private val audioSharingStreamSliderViewModelFactory: AudioSharingStreamSliderViewModel.Factory,
audioModeInteractor: AudioModeInteractor,
streamsInteractor: AudioSlidersInteractor,
) {
@@ -108,6 +110,7 @@ constructor(
is SliderType.Stream -> createStreamViewModel(type.stream)
is SliderType.MediaDeviceCast ->
createSessionViewModel(type.session)
+ is SliderType.AudioSharingStream -> createAudioSharingViewModel()
}
}
emit(viewModels)
@@ -138,11 +141,15 @@ constructor(
}
private fun CoroutineScope.createStreamViewModel(
- stream: AudioStream,
+ stream: AudioStream
): AudioStreamSliderViewModel {
return streamSliderViewModelFactory.create(
AudioStreamSliderViewModel.FactoryAudioStreamWrapper(stream),
this,
)
}
+
+ private fun CoroutineScope.createAudioSharingViewModel(): AudioSharingStreamSliderViewModel {
+ return audioSharingStreamSliderViewModelFactory.create(this)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/VolumePanelUiEvent.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/VolumePanelUiEvent.kt
index 8b8714fcca8c..d3a4fe86e827 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/VolumePanelUiEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/VolumePanelUiEvent.kt
@@ -34,6 +34,8 @@ enum class VolumePanelUiEvent(val metricId: Int) : UiEventLogger.UiEventEnum {
@UiEvent(doc = "The notification volume slider is touched")
VOLUME_PANEL_NOTIFICATION_SLIDER_TOUCHED(1642),
@UiEvent(doc = "The alarm volume slider is touched") VOLUME_PANEL_ALARM_SLIDER_TOUCHED(1643),
+ @UiEvent(doc = "The audio sharing volume slider is touched")
+ VOLUME_PANEL_AUDIO_SHARING_SLIDER_TOUCHED(2068),
@UiEvent(doc = "Live caption toggle is shown") VOLUME_PANEL_LIVE_CAPTION_TOGGLE_SHOWN(1644),
@UiEvent(doc = "Live caption toggle is gone") VOLUME_PANEL_LIVE_CAPTION_TOGGLE_GONE(1645),
@UiEvent(doc = "Live caption toggle is clicked") VOLUME_PANEL_LIVE_CAPTION_TOGGLE_CLICKED(1646),
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/GradientColorWallpaper.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/GradientColorWallpaper.kt
new file mode 100644
index 000000000000..c1fb0e80cafc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/GradientColorWallpaper.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wallpapers
+
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.service.wallpaper.WallpaperService
+import android.util.Log
+import android.view.SurfaceHolder
+import androidx.core.graphics.toRectF
+
+/** A wallpaper that shows a static gradient color image wallpaper. */
+class GradientColorWallpaper : WallpaperService() {
+
+ override fun onCreateEngine(): Engine = GradientColorWallpaperEngine()
+
+ inner class GradientColorWallpaperEngine : Engine() {
+ init {
+ setShowForAllUsers(true)
+ }
+
+ override fun onSurfaceRedrawNeeded(surfaceHolder: SurfaceHolder) {
+ drawFrameInternal(surfaceHolder)
+ }
+
+ private fun drawFrameInternal(surfaceHolder: SurfaceHolder) {
+ val context = displayContext ?: return
+ val surface = surfaceHolder.surface
+ var canvas: Canvas? = null
+ try {
+ canvas = surface.lockHardwareCanvas()
+ val destRectF = surfaceHolder.surfaceFrame.toRectF()
+ val toColor = context.getColor(com.android.internal.R.color.materialColorPrimary)
+
+ // TODO(b/384519696): Draw the actual gradient color wallpaper instead.
+ canvas.drawRect(destRectF, Paint().apply { color = toColor })
+ } catch (exception: IllegalStateException) {
+ Log.d(TAG, "Fail to draw in the canvas", exception)
+ } finally {
+ canvas?.let { surface.unlockCanvasAndPost(it) }
+ }
+ }
+ }
+
+ private companion object {
+ const val TAG = "GradientColorWallpaper"
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
index 9f6ad56335d7..c14cb87064ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
@@ -194,7 +194,7 @@ public class MenuAnimationControllerTest extends SysuiTestCase {
final Runnable onSpringAnimationsEndCallback = mock(Runnable.class);
mMenuAnimationController.setSpringAnimationsEndAction(onSpringAnimationsEndCallback);
- mMenuAnimationController.flingMenuThenSpringToEdge(/* x= */ 0, /* velocityX= */
+ mMenuAnimationController.flingMenuThenSpringToEdge(new PointF(), /* velocityX= */
100, /* velocityY= */ 100);
mMenuAnimationController.mPositionAnimations.values()
.forEach(animation -> verify((FlingAnimation) animation).addEndListener(
@@ -212,7 +212,7 @@ public class MenuAnimationControllerTest extends SysuiTestCase {
final Runnable onSpringAnimationsEndCallback = mock(Runnable.class);
mMenuAnimationController.setSpringAnimationsEndAction(onSpringAnimationsEndCallback);
- mMenuAnimationController.flingMenuThenSpringToEdge(/* x= */ 0, /* velocityX= */
+ mMenuAnimationController.flingMenuThenSpringToEdge(new PointF(), /* velocityX= */
200, /* velocityY= */ 200);
mMenuAnimationController.mPositionAnimations.values()
.forEach(animation -> verify((FlingAnimation) animation).addEndListener(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearanceTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearanceTest.java
new file mode 100644
index 000000000000..146488b523ad
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearanceTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.floatingmenu;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.graphics.Rect;
+import android.testing.TestableLooper;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Tests for {@link MenuViewAppearanceTest}. */
+@RunWith(AndroidJUnit4.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+public class MenuViewAppearanceTest extends SysuiTestCase {
+ static final Rect DRAGGABLE_BOUNDS = new Rect(0, 0, 10, 10);
+ static final int MENU_HEIGHT = 1;
+
+ @Test
+ public void avoidVerticalDisplayCutout_roomAbove_placesAbove() {
+ final int y = 2;
+ final Rect cutout = new Rect(0, 3, 0, 10);
+
+ final float end_y = MenuViewAppearance.avoidVerticalDisplayCutout(
+ y, MENU_HEIGHT, DRAGGABLE_BOUNDS, cutout);
+
+ assertThat(end_y + MENU_HEIGHT).isAtMost(cutout.top);
+ }
+
+ @Test
+ public void avoidVerticalDisplayCutout_roomBelow_placesBelow() {
+ final int y = 2;
+ final Rect cutout = new Rect(0, 0, 0, 5);
+
+ final float end_y = MenuViewAppearance.avoidVerticalDisplayCutout(
+ y, MENU_HEIGHT, DRAGGABLE_BOUNDS, cutout);
+
+ assertThat(end_y).isAtLeast(cutout.bottom);
+ }
+
+ @Test
+ public void avoidVerticalDisplayCutout_noRoom_noChange() {
+ final int y = 2;
+ final Rect cutout = new Rect(0, 0, 0, 10);
+
+ final float end_y = MenuViewAppearance.avoidVerticalDisplayCutout(
+ y, MENU_HEIGHT, DRAGGABLE_BOUNDS, cutout);
+
+ assertThat(end_y).isEqualTo(end_y);
+ }
+}
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 1500340c9d89..01fc868c716b 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
@@ -232,7 +232,6 @@ public class MenuViewLayerTest extends SysuiTestCase {
}
@Test
- @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void triggerDismissMenuAction_callsA11yManagerEnableShortcutsForTargets() {
final List<String> stubShortcutTargets = new ArrayList<>();
stubShortcutTargets.add(TEST_SELECT_TO_SPEAK_COMPONENT_NAME.flattenToString());
@@ -249,45 +248,6 @@ public class MenuViewLayerTest extends SysuiTestCase {
}
@Test
- @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
- public void triggerDismissMenuAction_matchA11yButtonTargetsResult() {
- mMenuViewLayer.mDismissMenuAction.run();
- verify(mSecureSettings).putStringForUser(
- Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, /* value= */ "",
- UserHandle.USER_CURRENT);
- }
-
- @Test
- @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
- public void triggerDismissMenuAction_matchEnabledA11yServicesResult() {
- setupEnabledAccessibilityServiceList();
-
- mMenuViewLayer.mDismissMenuAction.run();
- final String value = Settings.Secure.getStringForUser(mSpyContext.getContentResolver(),
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
- mSecureSettings.getRealUserHandle(UserHandle.USER_CURRENT));
-
- assertThat(value).isEqualTo("");
- }
-
- @Test
- @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
- public void triggerDismissMenuAction_hasHardwareKeyShortcut_keepEnabledStatus() {
- setupEnabledAccessibilityServiceList();
- final List<String> stubShortcutTargets = new ArrayList<>();
- stubShortcutTargets.add(TEST_SELECT_TO_SPEAK_COMPONENT_NAME.flattenToString());
- when(mStubAccessibilityManager.getAccessibilityShortcutTargets(
- ShortcutConstants.UserShortcutType.HARDWARE)).thenReturn(stubShortcutTargets);
-
- mMenuViewLayer.mDismissMenuAction.run();
- final String value = Settings.Secure.getStringForUser(mSpyContext.getContentResolver(),
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
- mSecureSettings.getRealUserHandle(UserHandle.USER_CURRENT));
-
- assertThat(value).isEqualTo(TEST_SELECT_TO_SPEAK_COMPONENT_NAME.flattenToString());
- }
-
- @Test
@EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
public void onEditAction_startsActivity() {
mockActivityQuery(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepositoryTest.kt
deleted file mode 100644
index 134c40da1033..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepositoryTest.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.android.systemui.bouncer.data.repository
-
-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.log.table.TableLogBuffer
-import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.time.SystemClock
-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
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class KeyguardBouncerRepositoryTest : SysuiTestCase() {
-
- @Mock private lateinit var systemClock: SystemClock
- @Mock private lateinit var bouncerLogger: TableLogBuffer
-
- private val kosmos = testKosmos()
- private val testScope = kosmos.testScope
-
- lateinit var underTest: KeyguardBouncerRepository
-
- @Before
- fun setup() {
- MockitoAnnotations.initMocks(this)
- underTest =
- KeyguardBouncerRepositoryImpl(
- systemClock,
- testScope.backgroundScope,
- bouncerLogger,
- )
- }
-
- @Test
- fun changingFlowValueTriggersLogging() =
- testScope.runTest {
- underTest.setPrimaryShow(true)
- Mockito.verify(bouncerLogger)
- .logChange(eq(""), eq("PrimaryBouncerShow"), value = eq(false), any())
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt
index 0508c2cf0426..072caa74df20 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt
@@ -31,6 +31,7 @@ import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.ui.viewmodel.communalTransitionViewModel
import com.android.systemui.controls.controller.ControlsControllerImplTest.Companion.eq
import com.android.systemui.dreams.DreamOverlayStateController
+import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
@@ -110,6 +111,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
@Mock private lateinit var dreamOverlayStateController: DreamOverlayStateController
@Mock private lateinit var shadeInteractor: ShadeInteractor
@Mock lateinit var logger: MediaViewLogger
+ @Mock lateinit var dumpManager: DumpManager
@Captor
private lateinit var wakefullnessObserver: ArgumentCaptor<(WakefulnessLifecycle.Observer)>
@Captor
@@ -166,6 +168,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
testScope.backgroundScope,
ResourcesSplitShadeStateController(),
logger,
+ dumpManager,
)
verify(wakefulnessLifecycle).addObserver(wakefullnessObserver.capture())
verify(statusBarStateController).addCallback(statusBarCallback.capture())
@@ -209,7 +212,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
any<MediaHostState>(),
anyBoolean(),
anyLong(),
- anyLong()
+ anyLong(),
)
val observer = wakefullnessObserver.value
assertNotNull("lifecycle observer wasn't registered", observer)
@@ -222,7 +225,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
any<MediaHostState>(),
anyBoolean(),
anyLong(),
- anyLong()
+ anyLong(),
)
}
@@ -236,7 +239,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
any<MediaHostState>(),
anyBoolean(),
anyLong(),
- anyLong()
+ anyLong(),
)
val observer = wakefullnessObserver.value
assertNotNull("lifecycle observer wasn't registered", observer)
@@ -249,7 +252,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
any<MediaHostState>(),
anyBoolean(),
anyLong(),
- anyLong()
+ anyLong(),
)
}
@@ -263,7 +266,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
any<MediaHostState>(),
anyBoolean(),
anyLong(),
- anyLong()
+ anyLong(),
)
clearInvocations(mediaCarouselController)
configurationController.notifyConfigurationChanged()
@@ -273,7 +276,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
any<MediaHostState>(),
anyBoolean(),
anyLong(),
- anyLong()
+ anyLong(),
)
}
@@ -287,7 +290,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
any<MediaHostState>(),
anyBoolean(),
anyLong(),
- anyLong()
+ anyLong(),
)
val observer = wakefullnessObserver.value
assertNotNull("lifecycle observer wasn't registered", observer)
@@ -299,7 +302,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
any<MediaHostState>(),
anyBoolean(),
anyLong(),
- anyLong()
+ anyLong(),
)
}
@@ -315,7 +318,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
any<MediaHostState>(),
eq(false),
anyLong(),
- anyLong()
+ anyLong(),
)
clearInvocations(mediaCarouselController)
@@ -327,7 +330,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
any<MediaHostState>(),
eq(false),
anyLong(),
- anyLong()
+ anyLong(),
)
// Let's make sure alpha is set
@@ -528,7 +531,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
nullable(),
eq(false),
anyLong(),
- anyLong()
+ anyLong(),
)
clearInvocations(mediaCarouselController)
@@ -539,7 +542,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
any<MediaHostState>(),
eq(false),
anyLong(),
- anyLong()
+ anyLong(),
)
}
@@ -559,7 +562,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
nullable(),
eq(false),
anyLong(),
- anyLong()
+ anyLong(),
)
clearInvocations(mediaCarouselController)
@@ -576,7 +579,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
any<MediaHostState>(),
eq(false),
anyLong(),
- anyLong()
+ anyLong(),
)
}
@@ -597,7 +600,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
nullable(),
eq(false),
anyLong(),
- anyLong()
+ anyLong(),
)
val captor = ArgumentCaptor.forClass(Boolean::class.java)
@@ -630,7 +633,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
nullable(),
eq(false),
anyLong(),
- anyLong()
+ anyLong(),
)
val captor = ArgumentCaptor.forClass(Boolean::class.java)
@@ -666,7 +669,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
nullable(),
eq(false),
anyLong(),
- anyLong()
+ anyLong(),
)
}
@@ -689,7 +692,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
nullable(),
eq(false),
anyLong(),
- anyLong()
+ anyLong(),
)
clearInvocations(mediaCarouselController)
@@ -704,7 +707,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
any<MediaHostState>(),
eq(false),
anyLong(),
- anyLong()
+ anyLong(),
)
}
@@ -734,7 +737,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
anyOrNull(),
eq(false),
anyLong(),
- anyLong()
+ anyLong(),
)
clearInvocations(mediaCarouselController)
@@ -749,7 +752,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
any<MediaHostState>(),
eq(false),
anyLong(),
- anyLong()
+ anyLong(),
)
}
@@ -788,7 +791,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
statusBarCallback.value.onStatePreChange(
StatusBarState.KEYGUARD,
- StatusBarState.SHADE_LOCKED
+ StatusBarState.SHADE_LOCKED,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
index a17f100904be..e5376d26840d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
@@ -88,8 +88,13 @@ public class RecordingControllerTest extends SysuiTestCase {
private ScreenRecordPermissionDialogDelegate.Factory
mScreenRecordPermissionDialogDelegateFactory;
@Mock
+ private ScreenRecordPermissionViewBinder.Factory
+ mScreenRecordPermissionViewBinderFactory;
+ @Mock
private ScreenRecordPermissionDialogDelegate mScreenRecordPermissionDialogDelegate;
@Mock
+ private ScreenRecordPermissionViewBinder mScreenRecordPermissionViewBinder;
+ @Mock
private SystemUIDialog mScreenRecordSystemUIDialog;
private RecordingController mController;
@@ -106,6 +111,8 @@ public class RecordingControllerTest extends SysuiTestCase {
.thenReturn(mScreenCaptureDisabledDialog);
when(mScreenRecordPermissionDialogDelegateFactory.create(any(), any(), anyInt(), any()))
.thenReturn(mScreenRecordPermissionDialogDelegate);
+ when(mScreenRecordPermissionViewBinderFactory.create(any(), anyInt(), any(), any()))
+ .thenReturn(mScreenRecordPermissionViewBinder);
when(mScreenRecordPermissionDialogDelegate.createDialog())
.thenReturn(mScreenRecordSystemUIDialog);
mController = new RecordingController(
@@ -116,7 +123,8 @@ public class RecordingControllerTest extends SysuiTestCase {
new RecordingControllerLogger(logcatLogBuffer("RecordingControllerTest")),
mMediaProjectionMetricsLogger,
mScreenCaptureDisabledDialogDelegate,
- mScreenRecordPermissionDialogDelegateFactory
+ mScreenRecordPermissionDialogDelegateFactory,
+ mScreenRecordPermissionViewBinderFactory
);
mController.addCallback(mCallback);
}
@@ -238,6 +246,26 @@ public class RecordingControllerTest extends SysuiTestCase {
}
@Test
+ public void testCreateScreenRecordPermissionViewBinder() {
+ ScreenRecordPermissionViewBinder viewBinder =
+ mController.createScreenRecordPermissionViewBinder(
+ /* onStartRecordingClicked= */ null);
+ assertThat(viewBinder).isEqualTo(mScreenRecordPermissionViewBinder);
+ }
+
+ @Test
+ public void testScreenCapturingAllowed_returnsFalseIsScreenCaptureDisabled() {
+ when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(false);
+ assertFalse(mController.isScreenCaptureDisabled());
+ }
+
+ @Test
+ public void testScreenCapturingNotAllowed_returnsTrueIsScreenCaptureDisabled() {
+ when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(true);
+ assertTrue(mController.isScreenCaptureDisabled());
+ }
+
+ @Test
public void testScreenCapturingAllowed_logsProjectionInitiated() {
when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
index 72d1db3affe8..281ce16b539f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
@@ -22,6 +22,7 @@ import static android.app.Notification.CATEGORY_EVENT;
import static android.app.Notification.CATEGORY_MESSAGE;
import static android.app.Notification.CATEGORY_REMINDER;
import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
+import static android.app.Notification.FLAG_PROMOTED_ONGOING;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
@@ -43,6 +44,8 @@ import android.graphics.drawable.Icon;
import android.media.session.MediaSession;
import android.os.Bundle;
import android.os.UserHandle;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
@@ -54,6 +57,8 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SbnBuilder;
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
@@ -280,6 +285,40 @@ public class NotificationEntryTest extends SysuiTestCase {
}
@Test
+ @EnableFlags({PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME})
+ public void isPromotedOngoing_noFlagOnNotif_false() {
+ mEntry.getSbn().getNotification().flags &= ~FLAG_PROMOTED_ONGOING;
+
+ assertFalse(mEntry.isPromotedOngoing());
+ }
+
+ @Test
+ @DisableFlags({PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME})
+ public void isPromotedOngoing_statusBarNotifChipsFlagAndUiFlagOff_false() {
+ mEntry.getSbn().getNotification().flags |= FLAG_PROMOTED_ONGOING;
+
+ assertFalse(mEntry.isPromotedOngoing());
+ }
+
+ @Test
+ @EnableFlags(PromotedNotificationUi.FLAG_NAME)
+ @DisableFlags(StatusBarNotifChips.FLAG_NAME)
+ public void isPromotedOngoing_uiFlagOnAndNotifHasFlag_true() {
+ mEntry.getSbn().getNotification().flags |= FLAG_PROMOTED_ONGOING;
+
+ assertTrue(mEntry.isPromotedOngoing());
+ }
+
+ @Test
+ @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+ @DisableFlags(PromotedNotificationUi.FLAG_NAME)
+ public void isPromotedOngoing_statusBarNotifChipsFlagOnAndNotifHasFlag_true() {
+ mEntry.getSbn().getNotification().flags |= FLAG_PROMOTED_ONGOING;
+
+ assertTrue(mEntry.isPromotedOngoing());
+ }
+
+ @Test
public void testIsNotificationVisibilityPrivate_true() {
assertTrue(mEntry.isNotificationVisibilityPrivate());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 3763282cdebc..6ac20d40f2dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -881,7 +881,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@EnableSceneContainer
public void testIsInsideScrollableRegion_noOffset() {
mStackScroller.setLeftTopRightBottom(0, 0, 1000, 2000);
- mStackScroller.setScrimClippingShape(createScrimShape(100, 500, 900, 2000));
+ mStackScroller.setClippingShape(createScrimShape(100, 500, 900, 2000));
MotionEvent event1 = transformEventForView(createMotionEvent(500f, 400f), mStackScroller);
assertThat(mStackScroller.isInScrollableRegion(event1)).isFalse();
@@ -900,7 +900,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@EnableSceneContainer
public void testIsInsideScrollableRegion_offset() {
mStackScroller.setLeftTopRightBottom(1000, 0, 2000, 2000);
- mStackScroller.setScrimClippingShape(createScrimShape(100, 500, 900, 2000));
+ mStackScroller.setClippingShape(createScrimShape(100, 500, 900, 2000));
MotionEvent event1 = transformEventForView(createMotionEvent(1500f, 400f), mStackScroller);
assertThat(mStackScroller.isInScrollableRegion(event1)).isFalse();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index 243be3dc142d..437ccb6a9821 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -37,7 +37,6 @@ import android.widget.FrameLayout
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.systemui.Flags as AconfigFlags
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestableContext
import com.android.systemui.battery.BatteryMeterView
@@ -52,7 +51,9 @@ import com.android.systemui.shade.ShadeViewController
import com.android.systemui.shade.StatusBarLongPressGestureDetector
import com.android.systemui.shade.display.StatusBarTouchShadeDisplayPolicy
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
+import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
import com.android.systemui.statusbar.data.repository.fakeStatusBarContentInsetsProviderStore
import com.android.systemui.statusbar.policy.Clock
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -62,7 +63,6 @@ import com.android.systemui.unfold.SysUIUnfoldComponent
import com.android.systemui.unfold.config.UnfoldTransitionConfig
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
import com.android.systemui.user.ui.viewmodel.StatusBarUserChipViewModel
-import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.view.ViewUtil
@@ -74,7 +74,6 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
@@ -82,6 +81,8 @@ import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -287,7 +288,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
}
@Test
- @DisableFlags(AconfigFlags.FLAG_STATUS_BAR_CONNECTED_DISPLAYS)
+ @DisableFlags(StatusBarConnectedDisplays.FLAG_NAME)
fun handleTouchEventFromStatusBar_touchOnPrimaryDisplay_statusBarConnectedDisplaysDisabled_shadeReceivesEvent() {
`when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
`when`(shadeViewController.isViewEnabled).thenReturn(true)
@@ -299,10 +300,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
}
@Test
- @EnableFlags(
- AconfigFlags.FLAG_STATUS_BAR_CONNECTED_DISPLAYS,
- AconfigFlags.FLAG_SHADE_WINDOW_GOES_AROUND,
- )
+ @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME, ShadeWindowGoesAround.FLAG_NAME)
fun handleTouchEventFromStatusBar_touchOnPrimaryDisplay_statusBarConnectedDisplaysEnabled_shadeWindowGoesAroundEnabled_shadeReceivesEvent() {
`when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
`when`(shadeViewController.isViewEnabled).thenReturn(true)
@@ -314,8 +312,8 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
}
@Test
- @EnableFlags(AconfigFlags.FLAG_STATUS_BAR_CONNECTED_DISPLAYS)
- @DisableFlags(AconfigFlags.FLAG_SHADE_WINDOW_GOES_AROUND)
+ @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+ @DisableFlags(ShadeWindowGoesAround.FLAG_NAME)
fun handleTouchEventFromStatusBar_touchOnPrimaryDisplay_statusBarConnectedDisplaysEnabled_shadeWindowGoesAroundDisabled_shadeReceivesEvent() {
`when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
`when`(shadeViewController.isViewEnabled).thenReturn(true)
@@ -327,7 +325,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
}
@Test
- @DisableFlags(AconfigFlags.FLAG_STATUS_BAR_CONNECTED_DISPLAYS)
+ @DisableFlags(StatusBarConnectedDisplays.FLAG_NAME)
fun handleTouchEventFromStatusBar_touchOnSecondaryDisplay_statusBarConnectedDisplaysDisabled_shadeReceivesEvent() {
`when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
`when`(shadeViewController.isViewEnabled).thenReturn(true)
@@ -339,10 +337,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
}
@Test
- @EnableFlags(
- AconfigFlags.FLAG_STATUS_BAR_CONNECTED_DISPLAYS,
- AconfigFlags.FLAG_SHADE_WINDOW_GOES_AROUND,
- )
+ @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME, ShadeWindowGoesAround.FLAG_NAME)
fun handleTouchEventFromStatusBar_touchOnSecondaryDisplay_statusBarConnectedDisplaysEnabled_shadeWindowGoesAroundEnabled_shadeReceivesEvent() {
`when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
`when`(shadeViewController.isViewEnabled).thenReturn(true)
@@ -354,8 +349,8 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
}
@Test
- @EnableFlags(AconfigFlags.FLAG_STATUS_BAR_CONNECTED_DISPLAYS)
- @DisableFlags(AconfigFlags.FLAG_SHADE_WINDOW_GOES_AROUND)
+ @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+ @DisableFlags(ShadeWindowGoesAround.FLAG_NAME)
fun handleTouchEventFromStatusBar_touchOnSecondaryDisplay_statusBarConnectedDisplaysEnabled_shadeWindowGoesAroundDisabled_shadeDoesNotReceiveEvent() {
`when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
`when`(shadeViewController.isViewEnabled).thenReturn(true)
@@ -441,27 +436,30 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
}
@Test
- @EnableFlags(AconfigFlags.FLAG_SHADE_WINDOW_GOES_AROUND)
+ @EnableFlags(ShadeWindowGoesAround.FLAG_NAME)
fun onTouch_actionDown_propagatesToDisplayPolicy() {
- controller.onTouch(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
+ val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
+ controller.onTouch(event)
- verify(statusBarTouchShadeDisplayPolicy).onStatusBarTouched(eq(mContext.displayId))
+ verify(statusBarTouchShadeDisplayPolicy).onStatusBarTouched(eq(event), any())
}
@Test
- @EnableFlags(AconfigFlags.FLAG_SHADE_WINDOW_GOES_AROUND)
+ @EnableFlags(ShadeWindowGoesAround.FLAG_NAME)
fun onTouch_actionUp_notPropagatesToDisplayPolicy() {
- controller.onTouch(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0))
+ val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0)
+ controller.onTouch(event)
- verify(statusBarTouchShadeDisplayPolicy, never()).onStatusBarTouched(any())
+ verify(statusBarTouchShadeDisplayPolicy, never()).onStatusBarTouched(any(), any())
}
@Test
- @DisableFlags(AconfigFlags.FLAG_SHADE_WINDOW_GOES_AROUND)
+ @DisableFlags(ShadeWindowGoesAround.FLAG_NAME)
fun onTouch_shadeWindowGoesAroundDisabled_notPropagatesToDisplayPolicy() {
- controller.onTouch(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
+ val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
+ controller.onTouch(event)
- verify(statusBarTouchShadeDisplayPolicy, never()).onStatusBarTouched(any())
+ verify(statusBarTouchShadeDisplayPolicy, never()).onStatusBarTouched(eq(event), any())
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index f9df6c79e140..0d0415e0d72d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -67,6 +67,7 @@ import com.android.systemui.statusbar.data.repository.StatusBarConfigurationCont
import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerStore;
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
+import com.android.systemui.statusbar.headsup.shared.StatusBarNoHunBehavior;
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager;
@@ -624,13 +625,14 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
assertEquals(View.GONE, getSecondaryOngoingActivityChipView().getVisibility());
}
- @Test
- @DisableFlags({
- StatusBarNotifChips.FLAG_NAME,
- StatusBarRootModernization.FLAG_NAME,
- StatusBarChipsModernization.FLAG_NAME
- })
- public void hasOngoingActivityButAlsoHun_chipHidden_notifsFlagOff() {
+ @Test
+ @DisableFlags({
+ StatusBarNotifChips.FLAG_NAME,
+ StatusBarRootModernization.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME,
+ StatusBarNoHunBehavior.FLAG_NAME,
+ })
+ public void hasOngoingActivityButAlsoHun_chipHidden_notifChipsFlagOff() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -646,8 +648,12 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
@Test
@EnableFlags({StatusBarNotifChips.FLAG_NAME})
- @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
- public void hasOngoingActivitiesButAlsoHun_chipsHidden_notifsFlagOn() {
+ @DisableFlags({
+ StatusBarRootModernization.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME,
+ StatusBarNoHunBehavior.FLAG_NAME
+ })
+ public void hasOngoingActivitiesButAlsoHun_chipsHidden_notifChipsFlagOn() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -662,13 +668,31 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
assertEquals(View.GONE, getSecondaryOngoingActivityChipView().getVisibility());
}
+ @Test
+ @EnableFlags({StatusBarNotifChips.FLAG_NAME, StatusBarNoHunBehavior.FLAG_NAME})
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void hasOngoingActivitiesButAlsoHun_noHunBehaviorFlagOn_chipsNotHidden() {
+ CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+
+ mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
+ /* hasPrimaryOngoingActivity= */ true,
+ /* hasSecondaryOngoingActivity= */ true,
+ /* shouldAnimate= */ false);
+ when(mHeadsUpAppearanceController.shouldHeadsUpStatusBarBeVisible()).thenReturn(true);
+
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ assertEquals(View.VISIBLE, getPrimaryOngoingActivityChipView().getVisibility());
+ assertEquals(View.VISIBLE, getSecondaryOngoingActivityChipView().getVisibility());
+ }
+
@Test
@DisableFlags({
StatusBarNotifChips.FLAG_NAME,
StatusBarRootModernization.FLAG_NAME,
StatusBarChipsModernization.FLAG_NAME
})
- public void primaryOngoingActivityEnded_chipHidden_notifsFlagOff() {
+ public void primaryOngoingActivityEnded_chipHidden_notifChipsFlagOff() {
resumeAndGetFragment();
// Ongoing activity started
@@ -948,9 +972,13 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
assertEquals(View.VISIBLE, getClockView().getVisibility());
}
- @Test
- @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
- public void disable_shouldHeadsUpStatusBarBeVisibleTrue_clockDisabled() {
+ @Test
+ @DisableFlags({
+ StatusBarRootModernization.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME,
+ StatusBarNoHunBehavior.FLAG_NAME,
+ })
+ public void disable_shouldHeadsUpStatusBarBeVisibleTrue_clockDisabled() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mHeadsUpAppearanceController.shouldHeadsUpStatusBarBeVisible()).thenReturn(true);
@@ -960,7 +988,11 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
}
@Test
- @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ @DisableFlags({
+ StatusBarRootModernization.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME,
+ StatusBarNoHunBehavior.FLAG_NAME,
+ })
public void disable_shouldHeadsUpStatusBarBeVisibleFalse_clockNotDisabled() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mHeadsUpAppearanceController.shouldHeadsUpStatusBarBeVisible()).thenReturn(false);
@@ -971,6 +1003,18 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
}
@Test
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+ public void disable_shouldHeadsUpStatusBarBeVisibleTrue_butNoHunBehaviorOn_clockNotDisabled() {
+ CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+ when(mHeadsUpAppearanceController.shouldHeadsUpStatusBarBeVisible()).thenReturn(true);
+
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ assertEquals(View.VISIBLE, getClockView().getVisibility());
+ }
+
+ @Test
public void setUp_fragmentCreatesDaggerComponent() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index d7456dfb33c3..6c60f55a3904 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -829,7 +829,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
testScope.runTest {
val latest by collectLastValue(underTest.defaultDataSubId)
- assertThat(latest).isEqualTo(INVALID_SUBSCRIPTION_ID)
+ assertThat(latest).isEqualTo(null)
val intent2 =
Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
@@ -856,6 +856,31 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
}
@Test
+ fun defaultDataSubId_filtersOutInvalidSubIds() =
+ testScope.runTest {
+ subscriptionManagerProxy.defaultDataSubId = INVALID_SUBSCRIPTION_ID
+ val latest by collectLastValue(underTest.defaultDataSubId)
+
+ assertThat(latest).isNull()
+ }
+
+ @Test
+ fun defaultDataSubId_filtersOutInvalidSubIds_fromValidToInvalid() =
+ testScope.runTest {
+ subscriptionManagerProxy.defaultDataSubId = 2
+ val latest by collectLastValue(underTest.defaultDataSubId)
+
+ assertThat(latest).isEqualTo(2)
+
+ val intent =
+ Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+ .putExtra(PhoneConstants.SUBSCRIPTION_KEY, INVALID_SUBSCRIPTION_ID)
+ fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intent)
+
+ assertThat(latest).isNull()
+ }
+
+ @Test
fun defaultDataSubId_fetchesCurrentOnRestart() =
testScope.runTest {
subscriptionManagerProxy.defaultDataSubId = 2
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/LocalBluetoothManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/LocalBluetoothManagerKosmos.kt
index eef89e7dac68..3d58cf58d7b9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/LocalBluetoothManagerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/LocalBluetoothManagerKosmos.kt
@@ -18,10 +18,12 @@ package com.android.systemui.bluetooth
import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
+import org.mockito.kotlin.mock
var Kosmos.localBluetoothManager: LocalBluetoothManager? by
Kosmos.Fixture {
- mock { whenever(cachedDeviceManager).thenReturn(cachedBluetoothDeviceManager) }
+ mock {
+ on { cachedDeviceManager }.thenReturn(cachedBluetoothDeviceManager)
+ on { profileManager }.thenReturn(localBluetoothProfileManager)
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/LocalBluetoothProfileManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/LocalBluetoothProfileManagerKosmos.kt
new file mode 100644
index 000000000000..34d7848a70aa
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/LocalBluetoothProfileManagerKosmos.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.bluetooth
+
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.localBluetoothProfileManager: LocalBluetoothProfileManager by Kosmos.Fixture { mock {} }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
index 703e2d1db200..f95f95721ce2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
@@ -23,9 +23,18 @@ class FakeKeyguardBouncerRepository @Inject constructor() : KeyguardBouncerRepos
override val primaryBouncerShowingSoon = _primaryBouncerShowingSoon.asStateFlow()
private val _primaryBouncerStartingToHide = MutableStateFlow(false)
override val primaryBouncerStartingToHide = _primaryBouncerStartingToHide.asStateFlow()
- private val _primaryBouncerDisappearAnimation = MutableStateFlow<Runnable?>(null)
override val primaryBouncerStartingDisappearAnimation =
- _primaryBouncerDisappearAnimation.asStateFlow()
+ MutableSharedFlow<Runnable?>(extraBufferCapacity = 2, replay = 1)
+
+ override fun isPrimaryBouncerStartingDisappearAnimation(): Boolean {
+ val replayCache = primaryBouncerStartingDisappearAnimation.replayCache
+ return if (!replayCache.isEmpty()) {
+ replayCache.last() != null
+ } else {
+ false
+ }
+ }
+
private val _primaryBouncerScrimmed = MutableStateFlow(false)
override val primaryBouncerScrimmed = _primaryBouncerScrimmed.asStateFlow()
private val _panelExpansionAmount = MutableStateFlow(KeyguardBouncerConstants.EXPANSION_HIDDEN)
@@ -53,6 +62,8 @@ class FakeKeyguardBouncerRepository @Inject constructor() : KeyguardBouncerRepos
MutableStateFlow(KeyguardSecurityModel.SecurityMode.Invalid)
override var bouncerDismissActionModel: BouncerDismissActionModel? = null
+ override fun isDebuggable() = true
+
override fun setPrimaryScrimmed(isScrimmed: Boolean) {
_primaryBouncerScrimmed.value = isScrimmed
}
@@ -74,7 +85,7 @@ class FakeKeyguardBouncerRepository @Inject constructor() : KeyguardBouncerRepos
}
override fun setPrimaryStartDisappearAnimation(runnable: Runnable?) {
- _primaryBouncerDisappearAnimation.value = runnable
+ primaryBouncerStartingDisappearAnimation.tryEmit(runnable)
}
override fun setPanelExpansion(panelExpansion: Float) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
index 487049740079..e30e92020706 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
@@ -33,10 +33,7 @@ import kotlinx.coroutines.flow.asStateFlow
@SysUISingleton
class FakeConfigurationRepository @Inject constructor() : ConfigurationRepository {
private val _onAnyConfigurationChange =
- MutableSharedFlow<Unit>(
- replay = 1,
- onBufferOverflow = BufferOverflow.DROP_OLDEST,
- )
+ MutableSharedFlow<Unit>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
override val onAnyConfigurationChange: Flow<Unit> = _onAnyConfigurationChange.asSharedFlow()
private val _onConfigurationChange =
@@ -53,7 +50,7 @@ class FakeConfigurationRepository @Inject constructor() : ConfigurationRepositor
get() = _onMovedToDisplay
private val _scaleForResolution = MutableStateFlow(1f)
- override val scaleForResolution: Flow<Float> = _scaleForResolution.asStateFlow()
+ override val scaleForResolution: StateFlow<Float> = _scaleForResolution.asStateFlow()
private val pixelSizes = mutableMapOf<Int, MutableStateFlow<Int>>()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/compose/Snapshot.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/compose/Snapshot.kt
index fb6699c44d62..91f1e1c3e0c8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/compose/Snapshot.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/compose/Snapshot.kt
@@ -17,18 +17,16 @@
package com.android.systemui.compose
import androidx.compose.runtime.snapshots.Snapshot
-import com.android.systemui.kosmos.runCurrent
import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
-import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
/**
* Runs the given test [block] in a [TestScope] that's set up such that the Compose snapshot state
- * is settled eagerly. This is the Compose equivalent to using an [UnconfinedTestDispatcher] or
- * using [runCurrent] a lot.
+ * writes are properly applied to the global snapshot. This is for instance necessary if your test
+ * is using `snapshotFlow {}` or any other mechanism that is observing the global snapshot.
*
- * Note that this shouldn't be needed or used in a Compose test environment.
+ * Note that this isn't needed in a Compose test environment, e.g. if you use the
+ * `Compose(Content)TestRule`.
*/
fun TestScope.runTestWithSnapshots(block: suspend TestScope.() -> Unit) {
val handle = Snapshot.registerGlobalWriteObserver { Snapshot.sendApplyNotifications() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DismissKeyguardInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissTransitionInteractor.kt
index 82a5311269f0..56a7b4db5455 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DismissKeyguardInteractor.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissTransitionInteractor.kt
@@ -18,10 +18,12 @@ package com.android.systemui.keyguard.domain.interactor
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
val Kosmos.keyguardDismissTransitionInteractor: KeyguardDismissTransitionInteractor by
Kosmos.Fixture {
KeyguardDismissTransitionInteractor(
+ scope = testScope,
repository = keyguardTransitionRepository,
fromLockscreenTransitionInteractor = fromLockscreenTransitionInteractor,
fromPrimaryBouncerTransitionInteractor = fromPrimaryBouncerTransitionInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelKosmos.kt
index 046284861e2b..4f3b8f3541e1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelKosmos.kt
@@ -20,12 +20,14 @@ import com.android.systemui.kosmos.Kosmos
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shade.ui.viewmodel.shadeHeaderViewModelFactory
+import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationStackAppearanceInteractor
val Kosmos.quickSettingsShadeOverlayContentViewModel: QuickSettingsShadeOverlayContentViewModel by
Kosmos.Fixture {
QuickSettingsShadeOverlayContentViewModel(
shadeInteractor = shadeInteractor,
sceneInteractor = sceneInteractor,
+ notificationStackAppearanceInteractor = notificationStackAppearanceInteractor,
shadeHeaderViewModelFactory = shadeHeaderViewModelFactory,
quickSettingsContainerViewModelFactory = quickSettingsContainerViewModelFactory,
)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt
index 636cb37adf03..aaef27d257c5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt
@@ -23,7 +23,11 @@ import com.android.systemui.kosmos.testScope
import com.android.systemui.shade.display.AnyExternalShadeDisplayPolicy
import com.android.systemui.shade.display.DefaultDisplayShadePolicy
import com.android.systemui.shade.display.ShadeDisplayPolicy
+import com.android.systemui.shade.display.ShadeExpansionIntent
import com.android.systemui.shade.display.StatusBarTouchShadeDisplayPolicy
+import com.android.systemui.shade.domain.interactor.notificationElement
+import com.android.systemui.shade.domain.interactor.qsElement
+import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.util.settings.fakeGlobalSettings
val Kosmos.defaultShadeDisplayPolicy: DefaultDisplayShadePolicy by
@@ -37,16 +41,20 @@ val Kosmos.anyExternalShadeDisplayPolicy: AnyExternalShadeDisplayPolicy by
)
}
-val Kosmos.focusBasedShadeDisplayPolicy: StatusBarTouchShadeDisplayPolicy by
+val Kosmos.statusBarTouchShadeDisplayPolicy: StatusBarTouchShadeDisplayPolicy by
Kosmos.Fixture {
StatusBarTouchShadeDisplayPolicy(
displayRepository = displayRepository,
backgroundScope = testScope.backgroundScope,
keyguardRepository = keyguardRepository,
shadeOnDefaultDisplayWhenLocked = false,
+ shadeInteractor = { shadeInteractor },
+ notificationElement = { notificationElement },
+ qsShadeElement = { qsElement },
)
}
-
+val Kosmos.shadeExpansionIntent: ShadeExpansionIntent by
+ Kosmos.Fixture { statusBarTouchShadeDisplayPolicy }
val Kosmos.shadeDisplaysRepository: MutableShadeDisplaysRepository by
Kosmos.Fixture {
ShadeDisplaysRepositoryImpl(
@@ -62,7 +70,7 @@ val Kosmos.shadeDisplayPolicies: Set<ShadeDisplayPolicy> by
setOf(
defaultShadeDisplayPolicy,
anyExternalShadeDisplayPolicy,
- focusBasedShadeDisplayPolicy,
+ statusBarTouchShadeDisplayPolicy,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt
index 6e44df833582..923de2dcbf68 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt
@@ -23,6 +23,7 @@ import com.android.systemui.kosmos.testScope
import com.android.systemui.shade.ShadeDisplayChangeLatencyTracker
import com.android.systemui.shade.ShadeWindowLayoutParams
import com.android.systemui.shade.data.repository.fakeShadeDisplaysRepository
+import com.android.systemui.shade.data.repository.shadeExpansionIntent
import java.util.Optional
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
@@ -49,5 +50,6 @@ val Kosmos.shadeDisplaysInteractor by
testScope.backgroundScope.coroutineContext,
mockedShadeDisplayChangeLatencyTracker,
Optional.of(shadeExpandedStateInteractor),
+ shadeExpansionIntent,
)
}
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 1dc7229a6506..32a30502a370 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
@@ -31,7 +31,6 @@ import com.android.systemui.statusbar.phone.dozeParameters
import com.android.systemui.statusbar.policy.data.repository.userSetupRepository
import com.android.systemui.statusbar.policy.domain.interactor.deviceProvisioningInteractor
import com.android.systemui.user.domain.interactor.userSwitcherInteractor
-import org.mockito.kotlin.mock
var Kosmos.baseShadeInteractor: BaseShadeInteractor by
Kosmos.Fixture {
@@ -73,7 +72,19 @@ val Kosmos.shadeInteractorImpl by
shadeModeInteractor = shadeModeInteractor,
)
}
-var Kosmos.mockShadeInteractor: ShadeInteractor by Kosmos.Fixture { mock() }
+var Kosmos.notificationElement: NotificationShadeElement by
+ Kosmos.Fixture {
+ NotificationShadeElement(shadeInteractor, testScope.backgroundScope.coroutineContext)
+ }
+var Kosmos.qsElement: QSShadeElement by
+ Kosmos.Fixture { QSShadeElement(shadeInteractor, testScope.backgroundScope.coroutineContext) }
val Kosmos.shadeExpandedStateInteractor by
- Kosmos.Fixture { ShadeExpandedStateInteractorImpl(shadeInteractor, testScope.backgroundScope) }
+ Kosmos.Fixture {
+ ShadeExpandedStateInteractorImpl(
+ shadeInteractor,
+ testScope.backgroundScope,
+ notificationElement,
+ qsElement,
+ )
+ }
val Kosmos.fakeShadeExpandedStateInteractor by Kosmos.Fixture { FakeShadeExpandedStateInteractor() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelKosmos.kt
index 01cac4c1e030..99323dbd7cce 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelKosmos.kt
@@ -31,3 +31,8 @@ val Kosmos.footerViewModel by Fixture {
shadeInteractor = shadeInteractor,
)
}
+val Kosmos.footerViewModelFactory: FooterViewModel.Factory by Fixture {
+ object : FooterViewModel.Factory {
+ override fun create() = footerViewModel
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
index c3bc744e09b0..fbc2a21b0888 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
@@ -24,7 +24,7 @@ import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.statusbar.domain.interactor.remoteInputInteractor
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.emptyshade.ui.viewmodel.emptyShadeViewModelFactory
-import com.android.systemui.statusbar.notification.footer.ui.viewmodel.footerViewModel
+import com.android.systemui.statusbar.notification.footer.ui.viewmodel.footerViewModelFactory
import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.notificationShelfViewModel
import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationStackInteractor
@@ -35,7 +35,7 @@ val Kosmos.notificationListViewModel by Fixture {
NotificationListViewModel(
notificationShelfViewModel,
hideListViewModel,
- Optional.of(footerViewModel),
+ footerViewModelFactory,
emptyShadeViewModelFactory,
Optional.of(notificationListLoggerViewModel),
activeNotificationsInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt
index 766b280334c8..f4e74fe0e6bb 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone.ongoingcall.shared.model
import android.app.PendingIntent
import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
/** Helper for building [OngoingCallModel.InCall] instances in tests. */
fun inCallModel(
@@ -25,4 +26,5 @@ fun inCallModel(
notificationIcon: StatusBarIconView? = null,
intent: PendingIntent? = null,
notificationKey: String = "test",
-) = OngoingCallModel.InCall(startTimeMs, notificationIcon, intent, notificationKey)
+ promotedContent: PromotedNotificationContentModel? = null,
+) = OngoingCallModel.InCall(startTimeMs, notificationIcon, intent, notificationKey, promotedContent)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeCarrierConfigRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeCarrierConfigRepository.kt
index adf6ca1d1710..eebfca79efe3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeCarrierConfigRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeCarrierConfigRepository.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository
import android.os.PersistableBundle
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
class FakeCarrierConfigRepository : CarrierConfigRepository {
@@ -24,8 +25,12 @@ class FakeCarrierConfigRepository : CarrierConfigRepository {
val configsById = mutableMapOf<Int, SystemUiCarrierConfig>()
- override fun getOrCreateConfigForSubId(subId: Int): SystemUiCarrierConfig =
- configsById.getOrPut(subId) { SystemUiCarrierConfig(subId, createDefaultTestConfig()) }
+ override fun getOrCreateConfigForSubId(maybeSubId: Int?): SystemUiCarrierConfig {
+ val subId = maybeSubId ?: INVALID_SUBSCRIPTION_ID
+ return configsById.getOrPut(subId) {
+ SystemUiCarrierConfig(subId, createDefaultTestConfig())
+ }
+ }
}
val CarrierConfigRepository.fake
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
index 3b8adb4a8307..352f6cf011e1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
@@ -55,7 +55,7 @@ class FakeMobileIconsInteractor(
override val filteredSubscriptions = MutableStateFlow<List<SubscriptionModel>>(listOf())
- override val defaultDataSubId = MutableStateFlow(DEFAULT_DATA_SUB_ID)
+ override val defaultDataSubId: MutableStateFlow<Int?> = MutableStateFlow(DEFAULT_DATA_SUB_ID)
private val _activeDataConnectionHasDataEnabled = MutableStateFlow(false)
override val activeDataConnectionHasDataEnabled = _activeDataConnectionHasDataEnabled
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioSharingRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioSharingRepository.kt
index 5da6ee95234c..6e76cf34c652 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioSharingRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioSharingRepository.kt
@@ -16,6 +16,7 @@
package com.android.systemui.volume.data.repository
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.volume.data.repository.AudioSharingRepository
import com.android.settingslib.volume.data.repository.GroupIdToVolumes
import kotlinx.coroutines.flow.MutableStateFlow
@@ -28,11 +29,17 @@ class FakeAudioSharingRepository : AudioSharingRepository {
MutableStateFlow(TEST_GROUP_ID_INVALID)
private val mutableSecondaryGroupId: MutableStateFlow<Int> =
MutableStateFlow(TEST_GROUP_ID_INVALID)
+ private val mutablePrimaryDevice: MutableStateFlow<CachedBluetoothDevice?> =
+ MutableStateFlow(null)
+ private val mutableSecondaryDevice: MutableStateFlow<CachedBluetoothDevice?> =
+ MutableStateFlow(null)
private val mutableVolumeMap: MutableStateFlow<GroupIdToVolumes> = MutableStateFlow(emptyMap())
override val inAudioSharing: StateFlow<Boolean> = mutableInAudioSharing
override val primaryGroupId: StateFlow<Int> = mutablePrimaryGroupId
override val secondaryGroupId: StateFlow<Int> = mutableSecondaryGroupId
+ override val primaryDevice: StateFlow<CachedBluetoothDevice?> = mutablePrimaryDevice
+ override val secondaryDevice: StateFlow<CachedBluetoothDevice?> = mutableSecondaryDevice
override val volumeMap: StateFlow<GroupIdToVolumes> = mutableVolumeMap
override suspend fun audioSharingAvailable(): Boolean = mutableAvailable
@@ -55,6 +62,14 @@ class FakeAudioSharingRepository : AudioSharingRepository {
mutableSecondaryGroupId.value = groupId
}
+ fun setPrimaryDevice(device: CachedBluetoothDevice?) {
+ mutablePrimaryDevice.value = device
+ }
+
+ fun setSecondaryDevice(device: CachedBluetoothDevice?) {
+ mutableSecondaryDevice.value = device
+ }
+
fun setVolumeMap(volumeMap: GroupIdToVolumes) {
mutableVolumeMap.value = volumeMap
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt
index 4fda95bab2ec..9f3150f7366a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt
@@ -23,6 +23,8 @@ import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.statusbar.notification.domain.interactor.notificationsSoundPolicyInteractor
import com.android.systemui.statusbar.policy.configurationController
+import com.android.systemui.util.time.fakeSystemClock
+import com.android.systemui.util.time.systemClock
import com.android.systemui.volume.dialog.domain.interactor.volumeDialogVisibilityInteractor
import com.android.systemui.volume.dialog.ringer.domain.volumeDialogRingerInteractor
import com.android.systemui.volume.dialog.shared.volumeDialogLogger
@@ -39,5 +41,6 @@ val Kosmos.volumeDialogRingerDrawerViewModel by
volumeDialogLogger = volumeDialogLogger,
visibilityInteractor = volumeDialogVisibilityInteractor,
configurationController = configurationController,
+ systemClock = fakeSystemClock,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponentKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponentKosmos.kt
index 4f79f7b4b41a..cb38cc3576ad 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponentKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponentKosmos.kt
@@ -18,6 +18,7 @@ package com.android.systemui.volume.dialog.sliders.dagger
import android.content.applicationContext
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.volumeDialogController
import com.android.systemui.statusbar.policy.data.repository.zenModeRepository
@@ -74,6 +75,7 @@ private fun Kosmos.setupVolumeDialogSliderComponent(
volumeDialogSliderType = type
applicationContext = parentKosmos.applicationContext
testScope = parentKosmos.testScope
+ testDispatcher = parentKosmos.testDispatcher
volumeDialogController = parentKosmos.volumeDialogController
mediaControllerInteractor = parentKosmos.mediaControllerInteractor
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModelKosmos.kt
index 63cd440a8633..b26081c40c38 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModelKosmos.kt
@@ -20,15 +20,19 @@ import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.util.time.systemClock
import com.android.systemui.volume.dialog.domain.interactor.volumeDialogVisibilityInteractor
+import com.android.systemui.volume.dialog.shared.volumeDialogLogger
import com.android.systemui.volume.dialog.sliders.domain.interactor.volumeDialogSliderInteractor
+import com.android.systemui.volume.dialog.sliders.domain.model.volumeDialogSliderType
val Kosmos.volumeDialogSliderViewModel by
Kosmos.Fixture {
VolumeDialogSliderViewModel(
+ sliderType = volumeDialogSliderType,
interactor = volumeDialogSliderInteractor,
visibilityInteractor = volumeDialogVisibilityInteractor,
coroutineScope = applicationCoroutineScope,
volumeDialogSliderIconProvider = volumeDialogSliderIconProvider,
systemClock = systemClock,
+ logger = volumeDialogLogger,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModelKosmos.kt
index 5531f7608b69..8fb60fdd5ab1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModelKosmos.kt
@@ -18,6 +18,7 @@ package com.android.systemui.volume.dialog.sliders.ui.viewmodel
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.volume.dialog.shared.volumeDialogLogger
import com.android.systemui.volume.dialog.sliders.dagger.volumeDialogSliderComponentFactory
import com.android.systemui.volume.dialog.sliders.domain.interactor.volumeDialogSlidersInteractor
@@ -27,5 +28,6 @@ val Kosmos.volumeDialogSlidersViewModel by
applicationCoroutineScope,
volumeDialogSlidersInteractor,
volumeDialogSliderComponentFactory,
+ volumeDialogLogger,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/FakeAudioSharingInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/FakeAudioSharingInteractor.kt
index 1fb5e77a3210..78cafbf99f49 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/FakeAudioSharingInteractor.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/FakeAudioSharingInteractor.kt
@@ -19,10 +19,11 @@ package com.android.systemui.volume.domain.interactor
import android.content.Context
import androidx.annotation.IntRange
import com.android.dream.lowlight.dagger.qualifiers.Application
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
-class FakeAudioSharingInteractor : AudioSharingInteractor {
+class FakeAudioSharingInteractor() : AudioSharingInteractor {
private val mutableInAudioSharing: MutableStateFlow<Boolean> = MutableStateFlow(false)
private val mutableVolume: MutableStateFlow<Int?> = MutableStateFlow(null)
private var audioSharingVolumeBarAvailable = false
@@ -31,6 +32,8 @@ class FakeAudioSharingInteractor : AudioSharingInteractor {
override val volume: Flow<Int?> = mutableVolume
override val volumeMin: Int = AUDIO_SHARING_VOLUME_MIN
override val volumeMax: Int = AUDIO_SHARING_VOLUME_MAX
+ override val primaryDevice = MutableStateFlow<CachedBluetoothDevice?>(null)
+ override val secondaryDevice = MutableStateFlow<CachedBluetoothDevice?>(null)
override suspend fun audioSharingVolumeBarAvailable(@Application context: Context): Boolean =
audioSharingVolumeBarAvailable
@@ -54,6 +57,14 @@ class FakeAudioSharingInteractor : AudioSharingInteractor {
audioSharingVolumeBarAvailable = available
}
+ fun setPrimaryDevice(device: CachedBluetoothDevice?) {
+ primaryDevice.value = device
+ }
+
+ fun setSecondaryDevice(device: CachedBluetoothDevice?) {
+ secondaryDevice.value = device
+ }
+
companion object {
const val AUDIO_SHARING_VOLUME_MIN = 0
const val AUDIO_SHARING_VOLUME_MAX = 255
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractorKosmos.kt
index 3bc920edd948..88734cd3b000 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractorKosmos.kt
@@ -20,6 +20,7 @@ import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.volume.data.repository.audioSystemRepository
import com.android.systemui.volume.domain.interactor.audioModeInteractor
+import com.android.systemui.volume.domain.interactor.audioSharingInteractor
import com.android.systemui.volume.mediaOutputInteractor
val Kosmos.audioSlidersInteractor by
@@ -29,5 +30,6 @@ val Kosmos.audioSlidersInteractor by
mediaOutputInteractor,
audioModeInteractor,
audioSystemRepository,
+ audioSharingInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelKosmos.kt
new file mode 100644
index 000000000000..96bc9722635a
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelKosmos.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.volume.panel.component.volume.slider.ui.viewmodel
+
+import android.content.applicationContext
+import com.android.internal.logging.uiEventLogger
+import com.android.systemui.haptics.slider.sliderHapticsViewModelFactory
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.volume.domain.interactor.audioSharingInteractor
+import kotlinx.coroutines.CoroutineScope
+
+val Kosmos.audioSharingStreamSliderViewModelFactory by
+ Kosmos.Fixture {
+ object : AudioSharingStreamSliderViewModel.Factory {
+ override fun create(coroutineScope: CoroutineScope): AudioSharingStreamSliderViewModel {
+ return AudioSharingStreamSliderViewModel(
+ coroutineScope,
+ applicationContext,
+ audioSharingInteractor,
+ uiEventLogger,
+ sliderHapticsViewModelFactory,
+ )
+ }
+ }
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelKosmos.kt
index a78670d7f1cc..88c716e0ab10 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelKosmos.kt
@@ -21,6 +21,7 @@ import com.android.internal.logging.uiEventLogger
import com.android.systemui.haptics.slider.sliderHapticsViewModelFactory
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor
+import com.android.systemui.volume.domain.interactor.audioSharingInteractor
import com.android.systemui.volume.domain.interactor.audioVolumeInteractor
import com.android.systemui.volume.shared.volumePanelLogger
import kotlinx.coroutines.CoroutineScope
@@ -39,6 +40,7 @@ val Kosmos.audioStreamSliderViewModelFactory by
applicationContext,
audioVolumeInteractor,
zenModeInteractor,
+ audioSharingInteractor,
uiEventLogger,
volumePanelLogger,
sliderHapticsViewModelFactory,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/VolumeSlidersViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/VolumeSlidersViewModelKosmos.kt
index 6e848ce26d9b..a6a4f8368941 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/VolumeSlidersViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/VolumeSlidersViewModelKosmos.kt
@@ -22,6 +22,7 @@ import com.android.systemui.volume.domain.interactor.audioModeInteractor
import com.android.systemui.volume.mediaDeviceSessionInteractor
import com.android.systemui.volume.mediaOutputInteractor
import com.android.systemui.volume.panel.component.volume.domain.interactor.audioSlidersInteractor
+import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.audioSharingStreamSliderViewModelFactory
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.audioStreamSliderViewModelFactory
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.castVolumeSliderViewModelFactory
@@ -33,6 +34,7 @@ val Kosmos.audioVolumeComponentViewModel by
mediaDeviceSessionInteractor,
audioStreamSliderViewModelFactory,
castVolumeSliderViewModelFactory,
+ audioSharingStreamSliderViewModelFactory,
audioModeInteractor,
audioSlidersInteractor,
)
diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/BuildScope.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/BuildScope.kt
index bd2173cd2393..c9fae70353f1 100644
--- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/BuildScope.kt
+++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/BuildScope.kt
@@ -100,7 +100,7 @@ interface BuildScope : HasNetwork, StateScope {
* observation of new emissions. It will however *not* cancel any running effects from previous
* emissions. To achieve this behavior, use [launchScope] or [asyncScope] to create a child
* build scope:
- * ``` kotlin
+ * ```
* val job = launchScope {
* events.observe { x ->
* launchEffect { longRunningEffect(x) }
@@ -141,7 +141,7 @@ interface BuildScope : HasNetwork, StateScope {
*
* By default, [builder] is only running while the returned [Events] is being
* [observed][observe]. If you want it to run at all times, simply add a no-op observer:
- * ``` kotlin
+ * ```
* events { ... }.apply { observe() }
* ```
*/
@@ -158,7 +158,7 @@ interface BuildScope : HasNetwork, StateScope {
*
* By default, [builder] is only running while the returned [Events] is being
* [observed][observe]. If you want it to run at all times, simply add a no-op observer:
- * ``` kotlin
+ * ```
* events { ... }.apply { observe() }
* ```
*
@@ -196,7 +196,7 @@ interface BuildScope : HasNetwork, StateScope {
* outside of the current Kairos transaction; when [transform] returns, the returned value is
* emitted from the result [Events] in a new transaction.
*
- * ``` kotlin
+ * ```
* fun <A, B> Events<A>.mapAsyncLatest(transform: suspend (A) -> B): Events<B> =
* mapLatestBuild { a -> asyncEvent { transform(a) } }.flatten()
* ```
@@ -571,7 +571,7 @@ interface BuildScope : HasNetwork, StateScope {
/**
* Shorthand for:
- * ``` kotlin
+ * ```
* flow.toEvents().holdState(initialValue)
* ```
*/
@@ -579,7 +579,7 @@ interface BuildScope : HasNetwork, StateScope {
/**
* Shorthand for:
- * ``` kotlin
+ * ```
* flow.scan(initialValue, operation).toEvents().holdState(initialValue)
* ```
*/
@@ -588,7 +588,7 @@ interface BuildScope : HasNetwork, StateScope {
/**
* Shorthand for:
- * ``` kotlin
+ * ```
* flow.scan(initialValue) { a, f -> f(a) }.toEvents().holdState(initialValue)
* ```
*/
@@ -665,7 +665,7 @@ interface BuildScope : HasNetwork, StateScope {
* be used to make further modifications to the Kairos network, and/or perform side-effects via
* [effect].
*
- * ``` kotlin
+ * ```
* fun <A> State<A>.observeBuild(block: BuildScope.(A) -> Unit = {}): Job = launchScope {
* block(sample())
* changes.observeBuild(block)
@@ -698,7 +698,7 @@ interface BuildScope : HasNetwork, StateScope {
* outside of the current Kairos transaction; when it completes, the returned [Events] emits in a
* new transaction.
*
- * ``` kotlin
+ * ```
* fun <A> BuildScope.asyncEvent(block: suspend () -> A): Events<A> =
* events { emit(block()) }.apply { observe() }
* ```
@@ -719,7 +719,7 @@ fun <A> BuildScope.asyncEvent(block: suspend () -> A): Events<A> =
* executed if this [BuildScope] is still active by that time. It can be deactivated due to a
* -Latest combinator, for example.
*
- * ``` kotlin
+ * ```
* fun BuildScope.effect(
* context: CoroutineContext = EmptyCoroutineContext,
* block: EffectScope.() -> Unit,
@@ -740,7 +740,7 @@ fun BuildScope.effect(
* done because the current [BuildScope] might be deactivated within this transaction, perhaps due
* to a -Latest combinator. If this happens, then the coroutine will never actually be started.
*
- * ``` kotlin
+ * ```
* fun BuildScope.launchEffect(block: suspend KairosScope.() -> Unit): Job =
* effect { effectCoroutineScope.launch { block() } }
* ```
@@ -757,7 +757,7 @@ fun BuildScope.launchEffect(block: suspend KairosCoroutineScope.() -> Unit): Job
* to a -Latest combinator. If this happens, then the coroutine will never actually be started.
*
* Shorthand for:
- * ``` kotlin
+ * ```
* fun <R> BuildScope.asyncEffect(block: suspend KairosScope.() -> R): Deferred<R> =
* CompletableDeferred<R>.apply {
* effect { effectCoroutineScope.launch { complete(block()) } }
@@ -789,7 +789,7 @@ fun BuildScope.launchScope(block: BuildSpec<*>): Job = asyncScope(block).second
*
* By default, [builder] is only running while the returned [Events] is being
* [observed][BuildScope.observe]. If you want it to run at all times, simply add a no-op observer:
- * ``` kotlin
+ * ```
* events { ... }.apply { observe() }
* ```
*
@@ -813,7 +813,7 @@ fun <In, Out> BuildScope.coalescingEvents(
*
* By default, [builder] is only running while the returned [Events] is being
* [observed][BuildScope.observe]. If you want it to run at all times, simply add a no-op observer:
- * ``` kotlin
+ * ```
* events { ... }.apply { observe() }
* ```
*
diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Events.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Events.kt
index 8f468c153743..1a13773d71bf 100644
--- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Events.kt
+++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Events.kt
@@ -105,7 +105,7 @@ class EventsLoop<A> : Events<A>() {
*
* Useful for recursive definitions.
*
- * ``` kotlin
+ * ```
* fun <A> Lazy<Events<A>>.defer() = deferredEvents { value }
* ```
*
@@ -122,7 +122,7 @@ class EventsLoop<A> : Events<A>() {
*
* Useful for recursive definitions.
*
- * ``` kotlin
+ * ```
* fun <A> DeferredValue<Events<A>>.defer() = deferredEvents { get() }
* ```
*
@@ -160,7 +160,7 @@ fun <A, B> Events<A>.mapMaybe(transform: TransactionScope.(A) -> Maybe<B>): Even
* Returns an [Events] that contains only the non-null results of applying [transform] to each value
* of the original [Events].
*
- * ``` kotlin
+ * ```
* fun <A> Events<A>.mapNotNull(transform: TransactionScope.(A) -> B?): Events<B> =
* mapMaybe { if (it == null) absent else present(it) }
* ```
@@ -201,7 +201,7 @@ fun <A, B> Events<A>.mapCheap(transform: TransactionScope.(A) -> B): Events<B> =
* Returns an [Events] that invokes [action] before each value of the original [Events] is emitted.
* Useful for logging and debugging.
*
- * ``` kotlin
+ * ```
* fun <A> Events<A>.onEach(action: TransactionScope.(A) -> Unit): Events<A> =
* map { it.also { action(it) } }
* ```
@@ -220,7 +220,7 @@ fun <A> Events<A>.onEach(action: TransactionScope.(A) -> Unit): Events<A> = map
* Splits an [Events] of pairs into a pair of [Events], where each returned [Events] emits half of
* the original.
*
- * ``` kotlin
+ * ```
* fun <A, B> Events<Pair<A, B>>.unzip(): Pair<Events<A>, Events<B>> {
* val lefts = map { it.first }
* val rights = map { it.second }
diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Filter.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Filter.kt
index 8ca5ac8652db..d412b849e441 100644
--- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Filter.kt
+++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Filter.kt
@@ -29,7 +29,7 @@ fun <A> Events<A>.filter(state: State<Boolean>): Events<A> = filter { state.samp
/**
* Returns an [Events] containing only values of the original [Events] that are not null.
*
- * ``` kotlin
+ * ```
* fun <A> Events<A?>.filterNotNull(): Events<A> = mapNotNull { it }
* ```
*
@@ -41,7 +41,7 @@ fun <A> Events<A?>.filterNotNull(): Events<A> = mapCheap { it.toMaybe() }.filter
/**
* Returns an [Events] containing only values of the original [Events] that are instances of [A].
*
- * ``` kotlin
+ * ```
* inline fun <reified A> Events<*>.filterIsInstance(): Events<A> =
* mapNotNull { it as? A }
* ```
@@ -55,7 +55,7 @@ inline fun <reified A> Events<*>.filterIsInstance(): Events<A> =
/**
* Returns an [Events] containing only values of the original [Events] that are present.
*
- * ``` kotlin
+ * ```
* fun <A> Events<Maybe<A>>.filterPresent(): Events<A> = mapMaybe { it }
* ```
*
@@ -69,7 +69,7 @@ fun <A> Events<Maybe<A>>.filterPresent(): Events<A> =
* Returns an [Events] containing only values of the original [Events] that satisfy the given
* [predicate].
*
- * ``` kotlin
+ * ```
* fun <A> Events<A>.filter(predicate: TransactionScope.(A) -> Boolean): Events<A> =
* mapMaybe { if (predicate(it)) present(it) else absent }
* ```
diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/GroupBy.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/GroupBy.kt
index 45da34ac9ae6..27fc1b4cf54c 100644
--- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/GroupBy.kt
+++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/GroupBy.kt
@@ -63,7 +63,7 @@ fun <K, A> Events<Map<K, A>>.groupByKey(numKeys: Int? = null): GroupedEvents<K,
* downstream [Events]. The downstream [Events] are associated with a [key][K], which is derived
* from each emission of the original [Events] via [extractKey].
*
- * ``` kotlin
+ * ```
* fun <K, A> Events<A>.groupBy(
* numKeys: Int? = null,
* extractKey: TransactionScope.(A) -> K,
@@ -108,7 +108,7 @@ class GroupedEvents<in K, out A> internal constructor(internal val impl: DemuxIm
* Using this is equivalent to `upstream.filter(predicate) to upstream.filter { !predicate(it) }`
* but is more efficient; specifically, [partition] will only invoke [predicate] once per element.
*
- * ``` kotlin
+ * ```
* fun <A> Events<A>.partition(
* predicate: TransactionScope.(A) -> Boolean
* ): Pair<Events<A>, Events<A>> =
@@ -133,7 +133,7 @@ fun <A> Events<A>.partition(
* [First]s and once for [Second]s, but is slightly more efficient; specifically, the
* [filterIsInstance] check is only performed once per element.
*
- * ``` kotlin
+ * ```
* fun <A, B> Events<Either<A, B>>.partitionEither(): Pair<Events<A>, Events<B>> =
* map { it.asThese() }.partitionThese()
* ```
diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Incremental.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Incremental.kt
index d88ae3b81349..02941bdded30 100644
--- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Incremental.kt
+++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Incremental.kt
@@ -62,7 +62,7 @@ fun <K, V> incrementalOf(value: Map<K, V>): Incremental<K, V> {
*
* Useful for recursive definitions.
*
- * ``` kotlin
+ * ```
* fun <A> Lazy<Incremental<K, V>>.defer() = deferredIncremental { value }
* ```
*/
@@ -78,7 +78,7 @@ fun <K, V> Lazy<Incremental<K, V>>.defer(): Incremental<K, V> = deferInline { va
*
* Useful for recursive definitions.
*
- * ``` kotlin
+ * ```
* fun <A> DeferredValue<Incremental<K, V>>.defer() = deferredIncremental { get() }
* ```
*/
diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Merge.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Merge.kt
index de9dca43b5d5..cc4ce53ca40a 100644
--- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Merge.kt
+++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Merge.kt
@@ -33,7 +33,7 @@ import com.android.systemui.kairos.util.map
* function is used to combine coincident emissions to produce the result value to be emitted by the
* merged [Events].
*
- * ``` kotlin
+ * ```
* fun <A> Events<A>.mergeWith(
* other: Events<A>,
* transformCoincidence: TransactionScope.(A, A) -> A = { a, _ -> a },
@@ -62,7 +62,7 @@ fun <A> Events<A>.mergeWith(
* Merges the given [Events] into a single [Events] that emits events from all. All coincident
* emissions are collected into the emitted [List], preserving the input ordering.
*
- * ``` kotlin
+ * ```
* fun <A> merge(vararg events: Events<A>): Events<List<A>> = events.asIterable().merge()
* ```
*
@@ -76,7 +76,7 @@ fun <A> merge(vararg events: Events<A>): Events<List<A>> = events.asIterable().m
* Merges the given [Events] into a single [Events] that emits events from all. In the case of
* coincident emissions, the emission from the left-most [Events] is emitted.
*
- * ``` kotlin
+ * ```
* fun <A> mergeLeft(vararg events: Events<A>): Events<A> = events.asIterable().mergeLeft()
* ```
*
@@ -92,7 +92,7 @@ fun <A> mergeLeft(vararg events: Events<A>): Events<A> = events.asIterable().mer
* function is used to combine coincident emissions to produce the result value to be emitted by the
* merged [Events].
*
- * ``` kotlin
+ * ```
* fun <A> merge(vararg events: Events<A>, transformCoincidence: (A, A) -> A): Events<A> =
* merge(*events).map { l -> l.reduce(transformCoincidence) }
* ```
@@ -117,7 +117,7 @@ fun <A> Iterable<Events<A>>.merge(): Events<List<A>> =
* coincident emissions, the emission from the left-most [Events] is emitted.
*
* Semantically equivalent to the following definition:
- * ``` kotlin
+ * ```
* fun <A> Iterable<Events<A>>.mergeLeft(): Events<A> =
* merge().mapCheap { it.first() }
* ```
@@ -135,7 +135,7 @@ fun <A> Iterable<Events<A>>.mergeLeft(): Events<A> =
* Creates a new [Events] that emits events from all given [Events]. All simultaneous emissions are
* collected into the emitted [List], preserving the input ordering.
*
- * ``` kotlin
+ * ```
* fun <A> Sequence<Events<A>>.merge(): Events<List<A>> = asIterable().merge()
* ```
*
@@ -148,7 +148,7 @@ fun <A> Iterable<Events<A>>.mergeLeft(): Events<A> =
* collected into the emitted [Map], and are given the same key of the associated [Events] in the
* input [Map].
*
- * ``` kotlin
+ * ```
* fun <K, A> Map<K, Events<A>>.merge(): Events<Map<K, A>> =
* asSequence()
* .map { (k, events) -> events.map { a -> k to a } }
@@ -173,7 +173,7 @@ fun <K, A> Map<K, Events<A>>.merge(): Events<Map<K, A>> =
* [Map.applyPatch][com.android.systemui.kairos.util.applyPatch].
*
* Conceptually this is equivalent to:
- * ``` kotlin
+ * ```
* fun <K, V> State<Map<K, V>>.mergeEventsIncrementally(): Events<Map<K, V>> =
* map { it.merge() }.switchEvents()
* ```
@@ -218,7 +218,7 @@ fun <K, V> Incremental<K, Events<V>>.mergeEventsIncrementally(): Events<Map<K, V
* [Map.applyPatch][com.android.systemui.kairos.util.applyPatch].
*
* Conceptually this is equivalent to:
- * ``` kotlin
+ * ```
* fun <K, V> State<Map<K, V>>.mergeEventsIncrementallyPromptly(): Events<Map<K, V>> =
* map { it.merge() }.switchEventsPromptly()
* ```
diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/State.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/State.kt
index 22ca83c6a15a..e8b005ec8788 100644
--- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/State.kt
+++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/State.kt
@@ -76,7 +76,7 @@ fun <A> stateOf(value: A): State<A> {
*
* Useful for recursive definitions.
*
- * ``` kotlin
+ * ```
* fun <A> Lazy<State<A>>.defer() = deferredState { value }
* ```
*/
@@ -91,7 +91,7 @@ fun <A> stateOf(value: A): State<A> {
*
* Useful for recursive definitions.
*
- * ``` kotlin
+ * ```
* fun <A> DeferredValue<State<A>>.defer() = deferredState { get() }
* ```
*/
@@ -150,7 +150,7 @@ fun <A, B> State<A>.mapCheapUnsafe(transform: KairosScope.(A) -> B): State<B> {
* Splits a [State] of pairs into a pair of [Events][State], where each returned [State] holds half
* of the original.
*
- * ``` kotlin
+ * ```
* fun <A, B> State<Pair<A, B>>.unzip(): Pair<State<A>, State<B>> {
* val first = map { it.first }
* val second = map { it.second }
@@ -186,7 +186,7 @@ fun <A, B> State<A>.flatMap(transform: KairosScope.(A) -> State<B>): State<B> {
/**
* Returns a [State] that behaves like the current value of the original [State].
*
- * ``` kotlin
+ * ```
* fun <A> State<State<A>>.flatten() = flatMap { it }
* ```
*
@@ -201,7 +201,7 @@ fun <A, B> State<A>.flatMap(transform: KairosScope.(A) -> State<B>): State<B> {
* recent value is used.
*
* Effectively equivalent to:
- * ``` kotlin
+ * ```
* ConflatedMutableEvents(kairosNetwork).holdState(initialValue)
* ```
*/
@@ -328,7 +328,7 @@ private inline fun <A> deferInline(crossinline block: InitScope.() -> State<A>):
* Like [changes] but also includes the old value of this [State].
*
* Shorthand for:
- * ``` kotlin
+ * ```
* stateChanges.map { WithPrev(previousValue = sample(), newValue = it) }
* ```
*/
diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/StateScope.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/StateScope.kt
index faeffe84e2e8..8020896d228a 100644
--- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/StateScope.kt
+++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/StateScope.kt
@@ -116,7 +116,7 @@ interface StateScope : TransactionScope {
* [Events] emitted from this, following the patch rules outlined in
* [Map.applyPatch][com.android.systemui.kairos.util.applyPatch].
*
- * ``` kotlin
+ * ```
* fun <K, V> Events<MapPatch<K, Events<V>>>.mergeEventsIncrementally(
* initialEvents: DeferredValue<Map<K, Events<V>>>,
* ): Events<Map<K, V>> =
@@ -135,7 +135,7 @@ interface StateScope : TransactionScope {
* [Events] emitted from this, following the patch rules outlined in
* [Map.applyPatch][com.android.systemui.kairos.util.applyPatch].
*
- * ``` kotlin
+ * ```
* fun <K, V> Events<MapPatch<K, Events<V>>>.mergeEventsIncrementallyPromptly(
* initialEvents: DeferredValue<Map<K, Events<V>>>,
* ): Events<Map<K, V>> =
@@ -155,7 +155,7 @@ interface StateScope : TransactionScope {
* [Events] emitted from this, following the patch rules outlined in
* [Map.applyPatch][com.android.systemui.kairos.util.applyPatch].
*
- * ``` kotlin
+ * ```
* fun <K, V> Events<MapPatch<K, Events<V>>>.mergeEventsIncrementally(
* initialEvents: Map<K, Events<V>>,
* ): Events<Map<K, V>> =
@@ -174,7 +174,7 @@ interface StateScope : TransactionScope {
* [Events] emitted from this, following the patch rules outlined in
* [Map.applyPatch][com.android.systemui.kairos.util.applyPatch].
*
- * ``` kotlin
+ * ```
* fun <K, V> Events<MapPatch<K, Events<V>>>.mergeEventsIncrementallyPromptly(
* initialEvents: Map<K, Events<V>>,
* ): Events<Map<K, V>> =
@@ -220,7 +220,7 @@ interface StateScope : TransactionScope {
* [mapLatestStateful], accumulation is not stopped with each subsequent emission of the
* original [Events].
*
- * ``` kotlin
+ * ```
* fun <A, B> Events<A>.mapStateful(transform: StateScope.(A) -> B): Events<B> =
* map { statefully { transform(it) } }.applyStatefuls()
* ```
@@ -234,7 +234,7 @@ interface StateScope : TransactionScope {
*
* Unlike [applyLatestStateful], state accumulation is not stopped with each state change.
*
- * ``` kotlin
+ * ```
* fun <A> State<Stateful<A>>.applyStatefuls(): State<A> =
* changes
* .applyStatefuls()
@@ -252,7 +252,7 @@ interface StateScope : TransactionScope {
* Returns an [Events] that acts like the most recent [Events] to be emitted from the original
* [Events].
*
- * ``` kotlin
+ * ```
* fun <A> Events<Events<A>>.flatten() = holdState(emptyEvents).switchEvents()
* ```
*
@@ -267,7 +267,7 @@ interface StateScope : TransactionScope {
* [transform] can perform state accumulation via its [StateScope] receiver. With each
* invocation of [transform], state accumulation from previous invocation is stopped.
*
- * ``` kotlin
+ * ```
* fun <A, B> Events<A>.mapLatestStateful(transform: StateScope.(A) -> B): Events<B> =
* map { statefully { transform(it) } }.applyLatestStateful()
* ```
@@ -282,7 +282,7 @@ interface StateScope : TransactionScope {
* [transform] can perform state accumulation via its [StateScope] receiver. With each
* invocation of [transform], state accumulation from previous invocation is stopped.
*
- * ``` kotlin
+ * ```
* fun <A, B> Events<A>.flatMapLatestStateful(
* transform: StateScope.(A) -> Events<B>
* ): Events<B> =
@@ -495,7 +495,7 @@ interface StateScope : TransactionScope {
*
* The optional [numKeys] argument is an optimization used to initialize the internal storage.
*
- * ``` kotlin
+ * ```
* fun <K, A, B> Events<MapPatch<K, A>>.mapLatestStatefulForKey(
* numKeys: Int? = null,
* transform: StateScope.(A) -> B,
@@ -516,7 +516,7 @@ interface StateScope : TransactionScope {
* If the original [Events] is emitting an event at this exact time, then it will be the only
* even emitted from the result [Events].
*
- * ``` kotlin
+ * ```
* fun <A> Events<A>.nextOnly(): Events<A> =
* EventsLoop<A>().apply {
* loopback = map { emptyEvents }.holdState(this@nextOnly).switchEvents()
@@ -535,7 +535,7 @@ interface StateScope : TransactionScope {
/**
* Returns an [Events] that skips the next emission of the original [Events].
*
- * ``` kotlin
+ * ```
* fun <A> Events<A>.skipNext(): Events<A> =
* nextOnly().map { this@skipNext }.holdState(emptyEvents).switchEvents()
* ```
@@ -554,7 +554,7 @@ interface StateScope : TransactionScope {
* If the original [Events] emits at the same time as [stop], then the returned [Events] will
* emit that value.
*
- * ``` kotlin
+ * ```
* fun <A> Events<A>.takeUntil(stop: Events<*>): Events<A> =
* stop.map { emptyEvents }.nextOnly().holdState(this).switchEvents()
* ```
@@ -586,7 +586,7 @@ interface StateScope : TransactionScope {
* Returns an [Events] that emits values from the original [Events] up to and including a value
* is emitted that satisfies [predicate].
*
- * ``` kotlin
+ * ```
* fun <A> Events<A>.takeUntil(predicate: TransactionScope.(A) -> Boolean): Events<A> =
* takeUntil(filter(predicate))
* ```
@@ -602,7 +602,7 @@ interface StateScope : TransactionScope {
* have been processed; this keeps the value of the [State] consistent during the entire Kairos
* transaction.
*
- * ``` kotlin
+ * ```
* fun <A, B> Events<A>.foldState(
* initialValue: B,
* transform: TransactionScope.(A, B) -> B,
@@ -630,7 +630,7 @@ interface StateScope : TransactionScope {
* have been processed; this keeps the value of the [State] consistent during the entire Kairos
* transaction.
*
- * ``` kotlin
+ * ```
* fun <A, B> Events<A>.foldStateDeferred(
* initialValue: DeferredValue<B>,
* transform: TransactionScope.(A, B) -> B,
@@ -663,7 +663,7 @@ interface StateScope : TransactionScope {
* have been processed; this keeps the value of the [State] consistent during the entire Kairos
* transaction.
*
- * ``` kotlin
+ * ```
* fun <A> Events<Stateful<A>>.holdLatestStateful(init: Stateful<A>): State<A> {
* val (changes, initApplied) = applyLatestStateful(init)
* return changes.holdStateDeferred(initApplied)
@@ -724,7 +724,7 @@ interface StateScope : TransactionScope {
* Returns an [Events] that wraps each emission of the original [Events] into an [IndexedValue],
* containing the emitted value and its index (starting from zero).
*
- * ``` kotlin
+ * ```
* fun <A> Events<A>.withIndex(): Events<IndexedValue<A>> {
* val index = fold(0) { _, oldIdx -> oldIdx + 1 }
* return sample(index) { a, idx -> IndexedValue(idx, a) }
@@ -740,7 +740,7 @@ interface StateScope : TransactionScope {
* Returns an [Events] containing the results of applying [transform] to each value of the
* original [Events] and its index (starting from zero).
*
- * ``` kotlin
+ * ```
* fun <A> Events<A>.mapIndexed(transform: TransactionScope.(Int, A) -> B): Events<B> {
* val index = foldState(0) { _, i -> i + 1 }
* return sample(index) { a, idx -> transform(idx, a) }
@@ -755,7 +755,7 @@ interface StateScope : TransactionScope {
/**
* Returns an [Events] where all subsequent repetitions of the same value are filtered out.
*
- * ``` kotlin
+ * ```
* fun <A> Events<A>.distinctUntilChanged(): Events<A> {
* val state: State<Any?> = holdState(Any())
* return filter { it != state.sample() }
@@ -774,7 +774,7 @@ interface StateScope : TransactionScope {
* Note that the returned [Events] will not emit anything until [other] has emitted at least one
* value.
*
- * ``` kotlin
+ * ```
* fun <A, B, C> Events<A>.sample(
* other: Events<B>,
* transform: TransactionScope.(A, B) -> C,
@@ -796,7 +796,7 @@ interface StateScope : TransactionScope {
* Returns a [State] that samples the [Transactional] held by the given [State] within the same
* transaction that the state changes.
*
- * ``` kotlin
+ * ```
* fun <A> State<Transactional<A>>.sampleTransactionals(): State<A> =
* changes
* .sampleTransactionals()
@@ -815,7 +815,7 @@ interface StateScope : TransactionScope {
* Note that this is less efficient than [State.map], which should be preferred if [transform]
* does not need access to [TransactionScope].
*
- * ``` kotlin
+ * ```
* fun <A, B> State<A>.mapTransactionally(transform: TransactionScope.(A) -> B): State<B> =
* map { transactionally { transform(it) } }.sampleTransactionals()
* ```
@@ -830,7 +830,7 @@ interface StateScope : TransactionScope {
* Note that this is less efficient than [combine], which should be preferred if [transform]
* does not need access to [TransactionScope].
*
- * ``` kotlin
+ * ```
* fun <A, B, Z> combineTransactionally(
* stateA: State<A>,
* stateB: State<B>,
@@ -895,7 +895,7 @@ interface StateScope : TransactionScope {
* Note that this is less efficient than [flatMap], which should be preferred if [transform]
* does not need access to [TransactionScope].
*
- * ``` kotlin
+ * ```
* fun <A, B> State<A>.flatMapTransactionally(
* transform: TransactionScope.(A) -> State<B>
* ): State<B> = map { transactionally { transform(it) } }.sampleTransactionals().flatten()
@@ -950,7 +950,7 @@ interface StateScope : TransactionScope {
* Returns an [Incremental] that reflects the state of the original [Incremental], but also adds
* / removes entries based on the state of the original's values.
*
- * ``` kotlin
+ * ```
* fun <K, V> Incremental<K, State<Maybe<V>>>.applyStateIncrementally(): Incremental<K, V> =
* mapValues { (_, v) -> v.changes }
* .mergeEventsIncrementallyPromptly()
@@ -971,7 +971,7 @@ interface StateScope : TransactionScope {
* / removes entries based on the [State] returned from applying [transform] to the original's
* entries.
*
- * ``` kotlin
+ * ```
* fun <K, V, U> Incremental<K, V>.mapIncrementalState(
* transform: KairosScope.(Map.Entry<K, V>) -> State<Maybe<U>>
* ): Incremental<K, U> = mapValues { transform(it) }.applyStateIncrementally()
@@ -986,7 +986,7 @@ interface StateScope : TransactionScope {
* / removes entries based on the [State] returned from applying [transform] to the original's
* entries, such that entries are added when that state is `true`, and removed when `false`.
*
- * ``` kotlin
+ * ```
* fun <K, V> Incremental<K, V>.filterIncrementally(
* transform: KairosScope.(Map.Entry<K, V>) -> State<Boolean>
* ): Incremental<K, V> = mapIncrementalState { entry ->
@@ -1004,7 +1004,7 @@ interface StateScope : TransactionScope {
* Returns an [Incremental] that samples the [Transactionals][Transactional] held by the
* original within the same transaction that the incremental [updates].
*
- * ``` kotlin
+ * ```
* fun <K, V> Incremental<K, Transactional<V>>.sampleTransactionals(): Incremental<K, V> =
* updates
* .map { patch -> patch.mapValues { (k, mv) -> mv.map { it.sample() } } }
@@ -1027,7 +1027,7 @@ interface StateScope : TransactionScope {
* Note that this is less efficient than [mapValues], which should be preferred if [transform]
* does not need access to [TransactionScope].
*
- * ``` kotlin
+ * ```
* fun <K, V, U> Incremental<K, V>.mapValuesTransactionally(
* transform: TransactionScope.(Map.Entry<K, V>) -> U
* ): Incremental<K, U> =
diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Transactional.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Transactional.kt
index cf98821fdadb..5050511a1371 100644
--- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Transactional.kt
+++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Transactional.kt
@@ -51,7 +51,7 @@ fun <A> transactionalOf(value: A): Transactional<A> =
*
* Useful for recursive definitions.
*
- * ``` kotlin
+ * ```
* fun <A> DeferredValue<Transactional<A>>.defer() = deferredTransactional { get() }
* ```
*/
@@ -67,7 +67,7 @@ fun <A> DeferredValue<Transactional<A>>.defer(): Transactional<A> = deferInline
*
* Useful for recursive definitions.
*
- * ``` kotlin
+ * ```
* fun <A> Lazy<Transactional<A>>.defer() = deferredTransactional { value }
* ```
*/
diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/store/MapK.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/store/MapK.kt
index e193a4957bd0..3dbc6f00c623 100644
--- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/store/MapK.kt
+++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/store/MapK.kt
@@ -21,28 +21,28 @@ package com.android.systemui.kairos.internal.store
*
* Let's say you want to write a class that is generic over both a map, and the type of data within
* the map:
- * ``` kotlin
+ * ```
* class Foo<TMap, TKey, TValue> {
* val container: TMap<TKey, TElement> // disallowed!
* }
* ```
*
* You can use `MapK` to represent the "higher-kinded" type variable `TMap`:
- * ``` kotlin
+ * ```
* class Foo<TMap, TKey, TValue> {
* val container: MapK<TMap, TKey, TValue> // OK!
* }
* ```
*
* Note that Kotlin will not let you use the generic type without parameters as `TMap`:
- * ``` kotlin
+ * ```
* val fooHk: MapK<HashMap, Int, String> // not allowed: HashMap requires two type parameters
* ```
*
* To work around this, you need to declare a special type-witness object. This object is only used
* at compile time and can be stripped out by a minifier because it's never used at runtime.
*
- * ``` kotlin
+ * ```
* class Foo<A, B> : MapK<FooWitness, A, B> { ... }
* object FooWitness
*
diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/util/MapPatch.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/util/MapPatch.kt
index 8fe41bc20dfa..dde5d822f052 100644
--- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/util/MapPatch.kt
+++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/util/MapPatch.kt
@@ -47,7 +47,7 @@ fun <K, V> Map<K, V>.applyPatch(patch: MapPatch<K, V>): Map<K, V> {
* Returns a [MapPatch] that, when applied, includes all of the values from the original [Map].
*
* Shorthand for:
- * ``` kotlin
+ * ```
* mapValues { (key, value) -> Maybe.present(value) }
* ```
*/
diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/util/Maybe.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/util/Maybe.kt
index 4754bc443329..4373705597ed 100644
--- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/util/Maybe.kt
+++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/util/Maybe.kt
@@ -69,7 +69,7 @@ object MaybeScope {
*
* This can be used instead of Kotlin's built-in nullability (`?.` and `?:`) operators when dealing
* with complex combinations of nullables:
- * ``` kotlin
+ * ```
* val aMaybe: Maybe<Any> = ...
* val bMaybe: Maybe<Any> = ...
* val result: String = maybe {
diff --git a/packages/Vcn/service-b/src/com/android/server/vcn/Vcn.java b/packages/Vcn/service-b/src/com/android/server/vcn/Vcn.java
index 369ef6ae6a3f..97f86b1bff5b 100644
--- a/packages/Vcn/service-b/src/com/android/server/vcn/Vcn.java
+++ b/packages/Vcn/service-b/src/com/android/server/vcn/Vcn.java
@@ -209,6 +209,8 @@ public class Vcn extends Handler {
this(vcnContext, subscriptionGroup, config, snapshot, vcnCallback, new Dependencies());
}
+ // WARNING: This constructor executes on the binder thread. Thread safety MUST be ensured when
+ // accessing data within this constructor and any methods called from here.
@VisibleForTesting(visibility = Visibility.PRIVATE)
public Vcn(
@NonNull VcnContext vcnContext,
diff --git a/packages/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java b/packages/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java
index 99c848f53c39..38fcf09145d9 100644
--- a/packages/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java
+++ b/packages/Vcn/service-b/src/com/android/server/vcn/VcnNetworkProvider.java
@@ -36,7 +36,6 @@ import android.net.vcn.VcnGatewayConnectionConfig;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
-import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Slog;
@@ -46,6 +45,7 @@ import com.android.modules.utils.HandlerExecutor;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
/**
@@ -56,12 +56,14 @@ import java.util.concurrent.Executor;
*
* @hide
*/
+// TODO(b/388919146): Implement a more generic solution to prevent concurrent modifications on
+// mListeners and mRequests
// TODO(b/374174952): Replace VANILLA_ICE_CREAM with BAKLAVA after Android B finalization
@TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
public class VcnNetworkProvider extends NetworkProvider {
private static final String TAG = VcnNetworkProvider.class.getSimpleName();
- private final Set<NetworkRequestListener> mListeners = new ArraySet<>();
+ private final Set<NetworkRequestListener> mListeners = ConcurrentHashMap.newKeySet();
private final Context mContext;
private final Handler mHandler;
@@ -72,7 +74,7 @@ public class VcnNetworkProvider extends NetworkProvider {
*
* <p>NetworkRequests are immutable once created, and therefore can be used as stable keys.
*/
- private final Set<NetworkRequest> mRequests = new ArraySet<>();
+ private final Set<NetworkRequest> mRequests = ConcurrentHashMap.newKeySet();
public VcnNetworkProvider(@NonNull Context context, @NonNull Looper looper) {
this(context, looper, new Dependencies());
diff --git a/packages/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/packages/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
index 6467af4355f6..c8c645f1276d 100644
--- a/packages/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
+++ b/packages/Vcn/service-b/src/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
@@ -138,6 +138,8 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor {
@NonNull private final Object mCancellationToken = new Object();
@NonNull private final PacketLossCalculator mPacketLossCalculator;
+ @Nullable private BroadcastReceiver mDeviceIdleReceiver;
+
@Nullable private IpSecTransformWrapper mInboundTransform;
@Nullable private IpSecTransformState mLastIpSecTransformState;
@@ -168,19 +170,21 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor {
// Register for system broadcasts to monitor idle mode change
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
+
+ mDeviceIdleReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(
+ intent.getAction())
+ && mPowerManager.isDeviceIdleMode()) {
+ mLastIpSecTransformState = null;
+ }
+ }
+ };
getVcnContext()
.getContext()
.registerReceiver(
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(
- intent.getAction())
- && mPowerManager.isDeviceIdleMode()) {
- mLastIpSecTransformState = null;
- }
- }
- },
+ mDeviceIdleReceiver,
intentFilter,
null /* broadcastPermission not required */,
mHandler);
@@ -338,7 +342,12 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor {
super.close();
if (mInboundTransform != null) {
- mInboundTransform.close();
+ mInboundTransform = null;
+ }
+
+ if (mDeviceIdleReceiver != null) {
+ getVcnContext().getContext().unregisterReceiver(mDeviceIdleReceiver);
+ mDeviceIdleReceiver = null;
}
}
diff --git a/packages/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java b/packages/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
index 14853440a129..55829a5fe978 100644
--- a/packages/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
+++ b/packages/Vcn/service-b/src/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
@@ -165,7 +165,7 @@ public abstract class NetworkMetricMonitor implements AutoCloseable {
}
}
- /** Set the IpSecTransform that applied to the Network being monitored */
+ /** Set the IpSecTransform that is applied to the Network being monitored */
public void setInboundTransform(@NonNull IpSecTransform inTransform) {
setInboundTransformInternal(new IpSecTransformWrapper(inTransform));
}
diff --git a/ravenwood/scripts/pta-framework.sh b/ravenwood/scripts/pta-framework.sh
new file mode 100755
index 000000000000..224ab59e2e09
--- /dev/null
+++ b/ravenwood/scripts/pta-framework.sh
@@ -0,0 +1,91 @@
+#!/bin/bash
+# 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.
+
+#
+# Use "ravehleper pta" to create a shell script which:
+# - Reads the text "policy" files
+# - Convert to java annotations (using sed)
+#
+
+set -e
+
+
+# Uncomment it to always build ravenhelper (slow)
+# ${BUILD_CMD:-m} ravenhelper
+
+# Get the target directory. Default to $ANDROID_BUILD_TOP.
+TARGET_DIR="${TARGET_DIR:-${ANDROID_BUILD_TOP?\$ANDROID_BUILD_TOP must be set}}"
+
+echo "Target dir=$TARGET_DIR"
+
+cd "$TARGET_DIR"
+
+# Add -v or -d as needed.
+extra_args="$@"
+
+OUT_SCRIPT="${OUT_SCRIPT:-/tmp/pta.sh}"
+
+rm -f "$OUT_SCRIPT"
+
+# If you want to run on other files, run this script with the following
+# env vars predefined.
+
+POLICIES="${POLICIES:-
+frameworks/base/ravenwood/texts/ravenwood-common-policies.txt
+frameworks/base/ravenwood/texts/ravenwood-framework-policies.txt
+}"
+
+SOURCES="${SOURCES:-
+frameworks/base/core/java/
+frameworks/base/graphics/java/
+}"
+
+AAC="${AAC:-frameworks/base/ravenwood/texts/ravenwood-annotation-allowed-classes.txt}"
+
+with_flag() {
+ local flag="$1"
+ shift
+
+ for arg in "$@"; do
+ echo "$flag $arg"
+ done
+}
+
+run() {
+ echo "Running: $*"
+ "$@"
+}
+
+run_pta() {
+ local extra_args="$@"
+
+ run ${RAVENHELPER_CMD:-ravenhelper pta} \
+ --output-script $OUT_SCRIPT \
+ --annotation-allowed-classes-file $AAC \
+ $(with_flag --policy-override-file $POLICIES) \
+ $(with_flag --src $SOURCES) \
+ $extra_args
+
+ if ! [[ -f $OUT_SCRIPT ]] ; then
+ # no operations generated.
+ exit 0
+ fi
+
+ echo
+ echo "Created script at $OUT_SCRIPT. Run it with: sh $OUT_SCRIPT"
+ return 0
+}
+
+run_pta "$extra_args" \ No newline at end of file
diff --git a/ravenwood/texts/ravenwood-common-policies.txt b/ravenwood/texts/ravenwood-common-policies.txt
index 83c31512eb70..fd4ea6cf40c2 100644
--- a/ravenwood/texts/ravenwood-common-policies.txt
+++ b/ravenwood/texts/ravenwood-common-policies.txt
@@ -1,5 +1,8 @@
# Ravenwood "policy" that should apply to all code.
+# The "no-pta" marker is used to exclude the lines from "ravenhelper pta",
+# which tries to convert policies to annotations.
+
# Keep all AIDL interfaces
class :aidl keepclass
@@ -13,8 +16,8 @@ class :sysprops keepclass
class :r keepclass
# Support APIs not available in standard JRE
-class java.io.FileDescriptor keep
+class java.io.FileDescriptor # no-pta
method getInt$ @com.android.ravenwood.RavenwoodJdkPatch.getInt$
method setInt$ @com.android.ravenwood.RavenwoodJdkPatch.setInt$
-class java.util.LinkedHashMap keep
+class java.util.LinkedHashMap # no-pta
method eldest @com.android.ravenwood.RavenwoodJdkPatch.eldest
diff --git a/ravenwood/texts/ravenwood-framework-policies.txt b/ravenwood/texts/ravenwood-framework-policies.txt
index 80126df1b8df..4033782c607e 100644
--- a/ravenwood/texts/ravenwood-framework-policies.txt
+++ b/ravenwood/texts/ravenwood-framework-policies.txt
@@ -1,62 +1,65 @@
# Ravenwood "policy" file for framework-minus-apex.
+# The "no-pta" marker is used to exclude the lines from "ravenhelper pta",
+# which tries to convert policies to annotations.
+
# To avoid VerifyError on nano proto files (b/324063814), we rename nano proto classes.
# Note: The "rename" directive must use slashes (/) as a package name separator.
rename com/.*/nano/ devicenano/
rename android/.*/nano/ devicenano/
# StatsD auto-generated
-class com.android.internal.util.FrameworkStatsLog keepclass
+class com.android.internal.util.FrameworkStatsLog keepclass # no-pta
# Exported to Mainline modules; cannot use annotations
-class com.android.internal.util.FastXmlSerializer keepclass
-class com.android.internal.util.FileRotator keepclass
-class com.android.internal.util.HexDump keepclass
-class com.android.internal.util.IndentingPrintWriter keepclass
-class com.android.internal.util.LocalLog keepclass
-class com.android.internal.util.MessageUtils keepclass
-class com.android.internal.util.TokenBucket keepclass
-class android.os.HandlerExecutor keepclass
-class android.util.BackupUtils keepclass
-class android.util.IndentingPrintWriter keepclass
-class android.util.LocalLog keepclass
-class android.util.Pair keepclass
-class android.util.Rational keepclass
+class com.android.internal.util.FastXmlSerializer keepclass # no-pta
+class com.android.internal.util.FileRotator keepclass # no-pta
+class com.android.internal.util.HexDump keepclass # no-pta
+class com.android.internal.util.IndentingPrintWriter keepclass # no-pta
+class com.android.internal.util.LocalLog keepclass # no-pta
+class com.android.internal.util.MessageUtils keepclass # no-pta
+class com.android.internal.util.TokenBucket keepclass # no-pta
+class android.os.HandlerExecutor keepclass # no-pta
+class android.util.BackupUtils keepclass # no-pta
+class android.util.IndentingPrintWriter keepclass # no-pta
+class android.util.LocalLog keepclass # no-pta
+class android.util.Pair keepclass # no-pta
+class android.util.Rational keepclass # no-pta
# From modules-utils; cannot use annotations
-class com.android.internal.util.Preconditions keepclass
-class com.android.internal.logging.InstanceId keepclass
-class com.android.internal.logging.InstanceIdSequence keepclass
-class com.android.internal.logging.UiEvent keepclass
-class com.android.internal.logging.UiEventLogger keepclass
+class com.android.internal.util.Preconditions keepclass # no-pta
+class com.android.internal.logging.InstanceId keepclass # no-pta
+class com.android.internal.logging.InstanceIdSequence keepclass # no-pta
+class com.android.internal.logging.UiEvent keepclass # no-pta
+class com.android.internal.logging.UiEventLogger keepclass # no-pta
# From modules-utils; cannot use annotations
-class com.android.modules.utils.BinaryXmlPullParser keepclass
-class com.android.modules.utils.BinaryXmlSerializer keepclass
-class com.android.modules.utils.FastDataInput keepclass
-class com.android.modules.utils.FastDataOutput keepclass
-class com.android.modules.utils.ModifiedUtf8 keepclass
-class com.android.modules.utils.TypedXmlPullParser keepclass
-class com.android.modules.utils.TypedXmlSerializer keepclass
+class com.android.modules.utils.BinaryXmlPullParser keepclass # no-pta
+class com.android.modules.utils.BinaryXmlSerializer keepclass # no-pta
+class com.android.modules.utils.FastDataInput keepclass # no-pta
+class com.android.modules.utils.FastDataOutput keepclass # no-pta
+class com.android.modules.utils.ModifiedUtf8 keepclass # no-pta
+class com.android.modules.utils.TypedXmlPullParser keepclass # no-pta
+class com.android.modules.utils.TypedXmlSerializer keepclass # no-pta
# Uri
-class android.net.Uri keepclass
-class android.net.UriCodec keepclass
+class android.net.Uri keepclass # no-pta
+class android.net.UriCodec keepclass # no-pta
# Telephony
-class android.telephony.PinResult keepclass
+class android.telephony.PinResult keepclass # no-pta
# Just enough to support mocking, no further functionality
-class android.content.BroadcastReceiver keep
+class android.content.BroadcastReceiver keep # no-pta
method <init> ()V keep
-class android.content.Context keep
+class android.content.Context keep # no-pta
method <init> ()V keep
- method getSystemService (Ljava/lang/Class;)Ljava/lang/Object; keep
-class android.content.pm.PackageManager keep
+ method getSystemService (Ljava/lang/Class;)Ljava/lang/Object; keep # no-pta
+class android.content.pm.PackageManager # no-pta
method <init> ()V keep
-class android.text.ClipboardManager keep
+class android.text.ClipboardManager keep # no-pta
method <init> ()V keep
# Just enough to allow ResourcesManager to run
-class android.hardware.display.DisplayManagerGlobal keep
+class android.hardware.display.DisplayManagerGlobal keep # no-pta
method getInstance ()Landroid/hardware/display/DisplayManagerGlobal; ignore
diff --git a/ravenwood/texts/ravenwood-services-policies.txt b/ravenwood/texts/ravenwood-services-policies.txt
index 530e5c8f5986..e3be9afdba5c 100644
--- a/ravenwood/texts/ravenwood-services-policies.txt
+++ b/ravenwood/texts/ravenwood-services-policies.txt
@@ -1,12 +1,15 @@
# Ravenwood "policy" file for services.core.
+# The "no-pta" marker is used to exclude the lines from "ravenhelper pta",
+# which tries to convert policies to annotations.
+
# Auto-generated from XSD
-class com.android.server.compat.config.Change keepclass
-class com.android.server.compat.config.Config keepclass
-class com.android.server.compat.config.XmlParser keepclass
-class com.android.server.compat.overrides.ChangeOverrides keepclass
-class com.android.server.compat.overrides.OverrideValue keepclass
-class com.android.server.compat.overrides.Overrides keepclass
-class com.android.server.compat.overrides.RawOverrideValue keepclass
-class com.android.server.compat.overrides.XmlParser keepclass
-class com.android.server.compat.overrides.XmlWriter keepclass \ No newline at end of file
+class com.android.server.compat.config.Change keepclass # no-pta
+class com.android.server.compat.config.Config keepclass # no-pta
+class com.android.server.compat.config.XmlParser keepclass # no-pta
+class com.android.server.compat.overrides.ChangeOverrides keepclass # no-pta
+class com.android.server.compat.overrides.OverrideValue keepclass # no-pta
+class com.android.server.compat.overrides.Overrides keepclass # no-pta
+class com.android.server.compat.overrides.RawOverrideValue keepclass # no-pta
+class com.android.server.compat.overrides.XmlParser keepclass # no-pta
+class com.android.server.compat.overrides.XmlWriter keepclass # no-pta \ No newline at end of file
diff --git a/ravenwood/tools/hoststubgen/scripts/dump-jar b/ravenwood/tools/hoststubgen/scripts/dump-jar
index 998357b70dff..02a6d25378bd 100755
--- a/ravenwood/tools/hoststubgen/scripts/dump-jar
+++ b/ravenwood/tools/hoststubgen/scripts/dump-jar
@@ -89,14 +89,33 @@ filter_output() {
# - Some other transient lines
# - Sometimes the javap shows mysterious warnings, so remove them too.
#
- # `/PATTERN-1/,/PATTERN-2/{//!d}` is a trick to delete lines between two patterns, without
- # the start and the end lines.
+ # Most conversion are simple per-line deletion or simple inline replacement with a regex.
+ #
+ # But removing the constant pool is a bit tricky. It looks like this in the output:
+ #---------------------------
+ #Constant pool:
+ # #1 = Methodref #31.#88 // java/lang/Object."<init>":()V
+ # #2 = Class #89 // java/lang/UnsupportedOperationException
+ # :
+ #{ // Or something, I'm not sure if it always ends with a "{".
+ #---------------------------
+ # i.e. we want to delete all lines from "Constant pool:" as long as the first character
+ # is a space.
+ #
+ # If we simply use '/^Constant pool:/,/^[^ ]/d', then it'll delete the "Constant pool:"
+ # line and "{" line too, but again the last line might be important, so we don't want to
+ # delete it.
+ #
+ # So we instead, use '/^Constant pool:/,/^[^ ]/{/^ /d}', which mean:
+ # between lines matching '/^Constant pool:/' and '/^[^ ]/', delete lines that start with
+ # a space. (=='/^ /d').
+ #
sed -e 's/#[0-9][0-9]*/#x/g' \
-e 's/^\( *\)[0-9][0-9]*:/\1x:/' \
- -e '/^Constant pool:/,/^[^ ]/{//!d}' \
+ -e '/^Constant pool:/,/^[^ ]/{/^ /d}' \
-e '/^ *line *[0-9][0-9]*: *[0-9][0-9]*$/d' \
- -e '/SHA-256 checksum/d' \
- -e '/Last modified/d' \
+ -e '/^ *SHA-256 checksum/d' \
+ -e '/^ *Last modified/d' \
-e '/^Classfile jar/d' \
-e '/\[warning\]/d'
else
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
index be1b6ca93869..9782f3d0f591 100644
--- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
+++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
@@ -69,9 +69,9 @@ interface PolicyFileProcessor {
fun onRename(pattern: Pattern, prefix: String)
/** "class" directive. */
- fun onSimpleClassStart(className: String)
+ fun onClassStart(className: String)
fun onSimpleClassPolicy(className: String, policy: FilterPolicyWithReason)
- fun onSimpleClassEnd(className: String)
+ fun onClassEnd(className: String)
fun onSubClassPolicy(superClassName: String, policy: FilterPolicyWithReason)
fun onRedirectionClass(fromClassName: String, toClassName: String)
@@ -162,10 +162,10 @@ class TextFileFilterPolicyBuilder(
)
}
- override fun onSimpleClassStart(className: String) {
+ override fun onClassStart(className: String) {
}
- override fun onSimpleClassEnd(className: String) {
+ override fun onClassEnd(className: String) {
}
override fun onSimpleClassPolicy(className: String, policy: FilterPolicyWithReason) {
@@ -273,20 +273,23 @@ class TextFileFilterPolicyParser {
private var rFilePolicy: FilterPolicyWithReason? = null
/** Name of the file that's currently being processed. */
- var filename: String? = null
+ var filename: String = ""
private set
/** 1-based line number in the current file */
var lineNumber = -1
private set
+ /** Current line */
+ var currentLineText = ""
+ private set
+
/**
* Parse a given "policy" file.
*/
fun parse(reader: Reader, inputName: String, processor: PolicyFileProcessor) {
filename = inputName
- log.i("Parsing text policy file $inputName ...")
this.processor = processor
BufferedReader(reader).use { rd ->
lineNumber = 0
@@ -297,6 +300,7 @@ class TextFileFilterPolicyParser {
break
}
lineNumber++
+ currentLineText = line
line = normalizeTextLine(line) // Remove comment and trim.
if (line.isEmpty()) {
continue
@@ -312,7 +316,7 @@ class TextFileFilterPolicyParser {
private fun finishLastClass() {
currentClassName?.let { className ->
- processor.onSimpleClassEnd(className)
+ processor.onClassEnd(className)
currentClassName = null
}
}
@@ -413,10 +417,10 @@ class TextFileFilterPolicyParser {
}
private fun parseClass(fields: Array<String>) {
- if (fields.size < 3) {
- throw ParseException("Class ('c') expects 2 fields.")
+ if (fields.size <= 1) {
+ throw ParseException("Class ('c') expects 1 or 2 fields.")
}
- val className = fields[1]
+ val className = fields[1].toHumanReadableClassName()
// superClass is set when the class name starts with a "*".
val superClass = resolveExtendingClass(className)
@@ -424,7 +428,9 @@ class TextFileFilterPolicyParser {
// :aidl, etc?
val classType = resolveSpecialClass(className)
- if (fields[2].startsWith("!")) {
+ val policyStr = if (fields.size > 2) { fields[2] } else { "" }
+
+ if (policyStr.startsWith("!")) {
if (classType != SpecialClass.NotSpecial) {
// We could support it, but not needed at least for now.
throw ParseException(
@@ -432,10 +438,12 @@ class TextFileFilterPolicyParser {
)
}
// It's a redirection class.
- val toClass = fields[2].substring(1)
+ val toClass = policyStr.substring(1)
+ currentClassName = className
+ processor.onClassStart(className)
processor.onRedirectionClass(className, toClass)
- } else if (fields[2].startsWith("~")) {
+ } else if (policyStr.startsWith("~")) {
if (classType != SpecialClass.NotSpecial) {
// We could support it, but not needed at least for now.
throw ParseException(
@@ -443,11 +451,24 @@ class TextFileFilterPolicyParser {
)
}
// It's a class-load hook
- val callback = fields[2].substring(1)
+ val callback = policyStr.substring(1)
+ currentClassName = className
+ processor.onClassStart(className)
processor.onClassLoadHook(className, callback)
} else {
- val policy = parsePolicy(fields[2])
+ // Special case: if it's a class directive with no policy, then it encloses
+ // members, but we don't apply any policy to the class itself.
+ // This is only allowed in a not-special case.
+ if (policyStr == "") {
+ if (classType == SpecialClass.NotSpecial && superClass == null) {
+ currentClassName = className
+ return
+ }
+ throw ParseException("Special class or subclass directive must have a policy")
+ }
+
+ val policy = parsePolicy(policyStr)
if (!policy.isUsableWithClasses) {
throw ParseException("Class can't have policy '$policy'")
}
@@ -457,7 +478,7 @@ class TextFileFilterPolicyParser {
// TODO: Duplicate check, etc
if (superClass == null) {
currentClassName = className
- processor.onSimpleClassStart(className)
+ processor.onClassStart(className)
processor.onSimpleClassPolicy(className, policy.withReason(FILTER_REASON))
} else {
processor.onSubClassPolicy(
diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/diff-and-update-golden.sh b/ravenwood/tools/hoststubgen/test-tiny-framework/diff-and-update-golden.sh
index 8408a18142eb..23699fd1dba4 100755
--- a/ravenwood/tools/hoststubgen/test-tiny-framework/diff-and-update-golden.sh
+++ b/ravenwood/tools/hoststubgen/test-tiny-framework/diff-and-update-golden.sh
@@ -37,8 +37,7 @@ SCRIPT_NAME="${0##*/}"
GOLDEN_DIR=${GOLDEN_DIR:-golden-output}
mkdir -p $GOLDEN_DIR
-# TODO(b/388562869) We shouldn't need `--ignore-matching-lines`, but the golden files may not have the "Constant pool:" lines.
-DIFF_CMD=${DIFF_CMD:-diff -u --ignore-blank-lines --ignore-space-change --ignore-matching-lines='^\(Constant.pool:\|{\)$'}
+DIFF_CMD=${DIFF_CMD:-./tiny-framework-dump-test.py run-diff}
update=0
three_way=0
@@ -63,12 +62,10 @@ done
shift $(($OPTIND - 1))
# Build the dump files, which are the input of this test.
-run ${BUILD_CMD:=m} dump-jar tiny-framework-dump-test
-
+run ${BUILD_CMD:-m} dump-jar tiny-framework-dump-test
# Get the path to the generate text files. (not the golden files.)
# We get them from $OUT/module-info.json
-
files=(
$(python3 -c '
import sys
@@ -78,7 +75,7 @@ import json
with open(sys.argv[1], "r") as f:
data = json.load(f)
- # Equivalent to: jq -r '.["tiny-framework-dump-test"]["installed"][]'
+ # Equivalent to: jq -r '.["tiny-framework-dump-test"]["installed"][]'
for path in data["tiny-framework-dump-test"]["installed"]:
if "golden-output" in path:
diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py
index c35d6d106c8d..761748265726 100755
--- a/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py
+++ b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py
@@ -28,9 +28,16 @@ GOLDEN_DIRS = [
# Run diff.
def run_diff(file1, file2):
- # TODO(b/388562869) We shouldn't need `--ignore-matching-lines`, but the golden files may not have the "Constant pool:" lines.
- command = ['diff', '-u', '--ignore-blank-lines',
+ command = ['diff', '-u',
+ '--ignore-blank-lines',
'--ignore-space-change',
+
+ # Ignore the class file version.
+ '--ignore-matching-lines=^ *\(major\|minor\) version:$',
+
+ # We shouldn't need `--ignore-matching-lines`, but somehow
+ # the golden files were generated without these lines for b/388562869,
+ # so let's just ignore them.
'--ignore-matching-lines=^\(Constant.pool:\|{\)$',
file1, file2]
print(' '.join(command))
@@ -85,4 +92,13 @@ class TestWithGoldenOutput(unittest.TestCase):
if __name__ == "__main__":
+ args = sys.argv
+
+ # This script is used by diff-and-update-golden.sh too.
+ if len(args) > 1 and args[1] == "run-diff":
+ if run_diff(args[2], args[3]):
+ sys.exit(0)
+ else:
+ sys.exit(1)
+
unittest.main(verbosity=2)
diff --git a/ravenwood/tools/ravenhelper/Android.bp b/ravenwood/tools/ravenhelper/Android.bp
new file mode 100644
index 000000000000..a7ee4684506e
--- /dev/null
+++ b/ravenwood/tools/ravenhelper/Android.bp
@@ -0,0 +1,26 @@
+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"],
+}
+
+java_binary_host {
+ name: "ravenhelper",
+ main_class: "com.android.platform.test.ravenwood.ravenhelper.RavenHelperMain",
+ srcs: ["src/**/*.kt"],
+ static_libs: [
+ "guava",
+ "hoststubgen-lib",
+ "junit",
+ "metalava-gradle-plugin-deps", // Get lint/PSI related classes from here.
+ "ow2-asm",
+ "ow2-asm-analysis",
+ "ow2-asm-commons",
+ "ow2-asm-tree",
+ "ow2-asm-util",
+ ],
+ visibility: ["//visibility:public"],
+}
diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/RavenHelperMain.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/RavenHelperMain.kt
new file mode 100644
index 000000000000..e6efbf6c5223
--- /dev/null
+++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/RavenHelperMain.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@file:JvmName("RavenHelperMain")
+package com.android.platform.test.ravenwood.ravenhelper
+
+/*
+ * This file contains the main entry point for the "ravenhelper" command, which
+ * contains subcommands to help various tasks.
+ */
+
+import com.android.hoststubgen.GeneralUserErrorException
+import com.android.hoststubgen.LogLevel
+import com.android.hoststubgen.executableName
+import com.android.hoststubgen.log
+import com.android.hoststubgen.runMainWithBoilerplate
+import com.android.platform.test.ravenwood.ravenhelper.policytoannot.PtaProcessor
+
+interface SubcommandHandler {
+ fun handle(args: List<String>)
+}
+
+fun usage() {
+ System.out.println("""
+ Usage:
+ ravenhelper SUBCOMMAND options...
+
+ Subcommands:
+ pta: "policy-to-annotations" Convert policy file to annotations.
+ (See the pta-framework.sh script for usage.) 1
+
+ """.trimIndent())
+}
+
+fun main(args: Array<String>) {
+ executableName = "RavenHelper"
+ log.setConsoleLogLevel(LogLevel.Info)
+
+ runMainWithBoilerplate {
+ log.i("$executableName started")
+
+ if (args.size == 0) {
+ usage()
+ return
+ }
+
+ // Find the subcommand handler.
+ val subcommand = args[0]
+ val handler: SubcommandHandler = when (subcommand) {
+ "pta" -> PtaProcessor()
+ else -> {
+ usage()
+ throw GeneralUserErrorException("Unknown subcommand '$subcommand'")
+ }
+ }
+
+ // Run the subcommand.
+ handler.handle(args.copyOfRange(1, args.size).toList())
+ }
+}
diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/Annotations.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/Annotations.kt
new file mode 100644
index 000000000000..4a11259a8ef7
--- /dev/null
+++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/Annotations.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.platform.test.ravenwood.ravenhelper.policytoannot
+
+import com.android.hoststubgen.filters.FilterPolicy
+
+
+/**
+ * This class knows about the Ravenwood annotations.
+ */
+class Annotations {
+ enum class Target {
+ Class,
+ Field,
+ Method,
+ }
+
+ fun get(policy: FilterPolicy, target: Target): String? {
+ return when (policy) {
+ FilterPolicy.Keep ->
+ if (target == Target.Class) {
+ "@android.ravenwood.annotation.RavenwoodKeepPartialClass"
+ } else {
+ "@android.ravenwood.annotation.RavenwoodKeep"
+ }
+ FilterPolicy.KeepClass ->
+ "@android.ravenwood.annotation.RavenwoodKeepWholeClass"
+ FilterPolicy.Substitute ->
+ "@android.ravenwood.annotation.RavenwoodReplace"
+ FilterPolicy.Redirect ->
+ "@android.ravenwood.annotation.RavenwoodRedirect"
+ FilterPolicy.Throw ->
+ "@android.ravenwood.annotation.RavenwoodThrow"
+ FilterPolicy.Ignore -> null // Ignore has no annotation. (because it's not very safe.)
+ FilterPolicy.Remove ->
+ "@android.ravenwood.annotation.RavenwoodRemove"
+ }
+ }
+
+ private fun withArg(annot: String, arg: String): String {
+ return "@$annot(\"$arg\")"
+ }
+
+ fun getClassLoadHookAnnotation(arg: String): String {
+ return withArg("android.ravenwood.annotation.RavenwoodClassLoadHook", arg)
+ }
+
+ fun getRedirectionClassAnnotation(arg: String): String {
+ return withArg("android.ravenwood.annotation.RavenwoodRedirectionClass", arg)
+ }
+}
+
diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/Operations.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/Operations.kt
new file mode 100644
index 000000000000..3531ba951b1c
--- /dev/null
+++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/Operations.kt
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.platform.test.ravenwood.ravenhelper.policytoannot
+
+/*
+ * This file contains classes and functions about file edit operations, such as
+ * "insert a line", "delete a line".
+ */
+
+
+import com.android.hoststubgen.log
+import java.io.BufferedWriter
+import java.io.File
+
+enum class SourceOperationType {
+ /** Insert a line */
+ Insert,
+
+ /** delete a line */
+ Delete,
+
+ /** Insert a text at the beginning of a line */
+ Prepend,
+}
+
+data class SourceOperation(
+ /** Target file to edit. */
+ val sourceFile: String,
+
+ /** 1-based line number. Use -1 to add at the end of the file. */
+ val lineNumber: Int,
+
+ /** Operation type.*/
+ val type: SourceOperationType,
+
+ /** Operand -- text to insert or prepend. Ignored for delete. */
+ val text: String = "",
+
+ /** Human-readable description of why this operation was created */
+ val description: String,
+) {
+ override fun toString(): String {
+ return "SourceOperation(sourceFile='$sourceFile', " +
+ "lineNumber=$lineNumber, type=$type, text='$text' desc='$description')"
+ }
+}
+
+/**
+ * Stores list of [SourceOperation]s for each file.
+ */
+class SourceOperations {
+ var size: Int = 0
+ private set
+ private val fileOperations = mutableMapOf<String, MutableList<SourceOperation>>()
+
+ fun add(op: SourceOperation) {
+ log.forVerbose {
+ log.v("Adding operation: $op")
+ }
+ size++
+ fileOperations[op.sourceFile]?.let { ops ->
+ ops.add(op)
+ return
+ }
+ fileOperations[op.sourceFile] = mutableListOf(op)
+ }
+
+ /**
+ * Get the collected [SourceOperation]s for each file.
+ */
+ fun getOperations(): MutableMap<String, MutableList<SourceOperation>> {
+ return fileOperations
+ }
+}
+
+/**
+ * Create a shell script to apply all the operations (using sed).
+ */
+fun createShellScript(ops: SourceOperations, writer: BufferedWriter) {
+ // File header.
+ // Note ${'$'} is an ugly way to put a dollar sign ($) in a multi-line string.
+ writer.write(
+ """
+ #!/bin/bash
+
+ set -e # Finish when any command fails.
+
+ function apply() {
+ local file="${'$'}1"
+
+ # The script is given via stdin. Write it to file.
+ local sed="/tmp/pta-script.sed.tmp"
+ cat > "${'$'}sed"
+
+ echo "Running: sed -i -f \"${'$'}sed\" \"${'$'}file\""
+
+ if ! sed -i -f "${'$'}sed" "${'$'}file" ; then
+ echo 'Failed!' 1>&2
+ return 1
+ fi
+ }
+
+ """.trimIndent()
+ )
+
+ ops.getOperations().toSortedMap().forEach { (origFile, ops) ->
+ val file = File(origFile).absolutePath
+
+ writer.write("\n")
+
+ writer.write("#")
+ writer.write("=".repeat(78))
+ writer.write("\n")
+
+ writer.write("\n")
+
+ writer.write("apply \"$file\" <<'__END_OF_SCRIPT__'\n")
+ toSedScript(ops, writer)
+ writer.write("__END_OF_SCRIPT__\n")
+ }
+
+ writer.write("\n")
+
+ writer.write("echo \"All files updated successfully!\"\n")
+ writer.flush()
+}
+
+/**
+ * Create a sed script to apply a list of operations.
+ */
+private fun toSedScript(ops: List<SourceOperation>, writer: BufferedWriter) {
+ ops.sortedBy { it.lineNumber }.forEach { op ->
+ if (op.text.contains('\n')) {
+ throw RuntimeException("Operation $op may not contain newlines.")
+ }
+
+ // Convert each operation to a sed operation. Examples:
+ //
+ // - Insert "abc" to line 2
+ // 2i\
+ // abc
+ //
+ // - Insert "abc" to the end of the file
+ // $a\
+ // abc
+ //
+ // - Delete line 2
+ // 2d
+ //
+ // - Prepend abc to line 2
+ // 2s/^/abc/
+ //
+ // The line numbers are all the line numbers in the original file. Even though
+ // the script itself will change them because of inserts and deletes, we don't need to
+ // change the line numbers in the script.
+
+ // Write the target line number.
+ writer.write("\n")
+ writer.write("# ${op.description}\n")
+ if (op.lineNumber >= 0) {
+ writer.write(op.lineNumber.toString())
+ } else {
+ writer.write("$")
+ }
+
+ when (op.type) {
+ SourceOperationType.Insert -> {
+ if (op.lineNumber >= 0) {
+ writer.write("i\\\n") // "Insert"
+ } else {
+ // If it's the end of the file, we need to use "a" (append)
+ writer.write("a\\\n")
+ }
+ writer.write(op.text)
+ writer.write("\n")
+ }
+ SourceOperationType.Delete -> {
+ writer.write("d\n")
+ }
+ SourceOperationType.Prepend -> {
+ if (op.text.contains('/')) {
+ TODO("Operation $op contains character(s) that needs to be escaped.")
+ }
+ writer.write("s/^/${op.text}/\n")
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaOptions.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaOptions.kt
new file mode 100644
index 000000000000..08bd95fd532b
--- /dev/null
+++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaOptions.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.platform.test.ravenwood.ravenhelper.policytoannot
+
+import com.android.hoststubgen.ArgIterator
+import com.android.hoststubgen.ArgumentsException
+import com.android.hoststubgen.SetOnce
+import com.android.hoststubgen.ensureFileExists
+import com.android.hoststubgen.log
+
+/**
+ * Options for the "ravenhelper pta" subcommand.
+ */
+class PtaOptions(
+ /** Text policy files */
+ var policyOverrideFiles: MutableList<String> = mutableListOf(),
+
+ /** Annotation allowed list file. */
+ var annotationAllowedClassesFile: SetOnce<String?> = SetOnce(null),
+
+ /** Source files or directories. */
+ var sourceFilesOrDirectories: MutableList<String> = mutableListOf(),
+
+ /** Output script file. */
+ var outputScriptFile: SetOnce<String?> = SetOnce(null),
+
+ /** Dump the operations (for debugging) */
+ var dumpOperations: SetOnce<Boolean> = SetOnce(false),
+) {
+ companion object {
+ fun parseArgs(args: List<String>): PtaOptions {
+ val ret = PtaOptions()
+ val ai = ArgIterator.withAtFiles(args.toTypedArray())
+
+ while (true) {
+ val arg = ai.nextArgOptional() ?: break
+
+ fun nextArg(): String = ai.nextArgRequired(arg)
+
+ if (log.maybeHandleCommandLineArg(arg) { nextArg() }) {
+ continue
+ }
+ try {
+ when (arg) {
+ // TODO: Write help
+ "-h", "--help" -> TODO("Help is not implemented yet")
+
+ "-p", "--policy-override-file" ->
+ ret.policyOverrideFiles.add(nextArg().ensureFileExists())
+
+ "-a", "--annotation-allowed-classes-file" ->
+ ret.annotationAllowedClassesFile.set(nextArg().ensureFileExists())
+
+ "-s", "--src" ->
+ ret.sourceFilesOrDirectories.add(nextArg().ensureFileExists())
+
+ "--dump" ->
+ ret.dumpOperations.set(true)
+
+ "-o", "--output-script" ->
+ ret.outputScriptFile.set(nextArg())
+
+ else -> throw ArgumentsException("Unknown option: $arg")
+ }
+ } catch (e: SetOnce.SetMoreThanOnceException) {
+ throw ArgumentsException("Duplicate or conflicting argument found: $arg")
+ }
+ }
+
+ if (ret.policyOverrideFiles.size == 0) {
+ throw ArgumentsException("Must specify at least one policy file")
+ }
+
+ if (ret.sourceFilesOrDirectories.size == 0) {
+ throw ArgumentsException("Must specify at least one source path")
+ }
+
+ return ret
+ }
+ }
+
+ override fun toString(): String {
+ return """
+ PtaOptions{
+ policyOverrideFiles=$policyOverrideFiles
+ annotationAllowedClassesFile=$annotationAllowedClassesFile
+ sourceFilesOrDirectories=$sourceFilesOrDirectories
+ outputScriptFile=$outputScriptFile
+ dumpOperations=$dumpOperations
+ }
+ """.trimIndent()
+ }
+} \ No newline at end of file
diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt
new file mode 100644
index 000000000000..5984e4fc8f9f
--- /dev/null
+++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt
@@ -0,0 +1,479 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.platform.test.ravenwood.ravenhelper.policytoannot
+
+import com.android.hoststubgen.LogLevel
+import com.android.hoststubgen.asm.CLASS_INITIALIZER_NAME
+import com.android.hoststubgen.asm.toJvmClassName
+import com.android.hoststubgen.filters.FilterPolicyWithReason
+import com.android.hoststubgen.filters.PolicyFileProcessor
+import com.android.hoststubgen.filters.SpecialClass
+import com.android.hoststubgen.filters.TextFileFilterPolicyParser
+import com.android.hoststubgen.filters.TextFilePolicyMethodReplaceFilter
+import com.android.hoststubgen.log
+import com.android.hoststubgen.utils.ClassFilter
+import com.android.platform.test.ravenwood.ravenhelper.SubcommandHandler
+import com.android.platform.test.ravenwood.ravenhelper.psi.createUastEnvironment
+import com.android.platform.test.ravenwood.ravenhelper.sourcemap.AllClassInfo
+import com.android.platform.test.ravenwood.ravenhelper.sourcemap.ClassInfo
+import com.android.platform.test.ravenwood.ravenhelper.sourcemap.MethodInfo
+import com.android.platform.test.ravenwood.ravenhelper.sourcemap.SourceLoader
+import java.io.BufferedWriter
+import java.io.FileOutputStream
+import java.io.FileReader
+import java.io.OutputStreamWriter
+import java.util.regex.Pattern
+
+/**
+ * This is the main routine of the "pta" -- policy-to-annotation -- subcommands.
+ */
+class PtaProcessor : SubcommandHandler {
+ override fun handle(args: List<String>) {
+ val options = PtaOptions.parseArgs(args)
+
+ log.v("Options: $options")
+
+ val converter = TextPolicyToAnnotationConverter(
+ options.policyOverrideFiles,
+ options.sourceFilesOrDirectories,
+ options.annotationAllowedClassesFile.get,
+ Annotations(),
+ options.dumpOperations.get || log.isEnabled(LogLevel.Debug),
+ )
+ converter.process()
+
+ val ops = converter.resultOperations
+
+ if (ops.size == 0) {
+ log.i("No files need to be updated.")
+ return
+ }
+
+ val scriptWriter = BufferedWriter(OutputStreamWriter(
+ options.outputScriptFile.get?.let { file ->
+ FileOutputStream(file)
+ } ?: System.out
+ ))
+
+ scriptWriter.use { writer ->
+ options.outputScriptFile.get?.let {
+ log.i("Creating script file at $it ...")
+ }
+ createShellScript(ops, writer)
+ }
+ }
+}
+
+/**
+ * This class implements the actual logic.
+ */
+private class TextPolicyToAnnotationConverter(
+ val policyFiles: List<String>,
+ val sourceFilesOrDirectories: List<String>,
+ val annotationAllowedClassesFile: String?,
+ val annotations: Annotations,
+ val dumpOperations: Boolean,
+) {
+ private val annotationAllowedClasses: ClassFilter = annotationAllowedClassesFile.let { file ->
+ if (file == null) {
+ ClassFilter.newNullFilter(true) // Allow all classes
+ } else {
+ ClassFilter.loadFromFile(file, false)
+ }
+ }
+
+ val resultOperations = SourceOperations()
+ private val classes = AllClassInfo()
+ private val policyParser = TextFileFilterPolicyParser()
+ private val annotationNeedingClasses = mutableSetOf<String>()
+
+ /**
+ * Entry point.
+ */
+ fun process() {
+ // First, load
+ val env = createUastEnvironment()
+ try {
+ loadSources()
+
+ processPolicies()
+
+ addToAnnotationsAllowedListFile()
+
+ if (dumpOperations) {
+ log.withIndent {
+ resultOperations.getOperations().toSortedMap().forEach { (file, ops) ->
+ log.i("ops: $file")
+ ops.forEach { op ->
+ log.i(" line: ${op.lineNumber}: ${op.type}: \"${op.text}\" " +
+ "(${op.description})")
+ }
+ }
+ }
+ }
+ } finally {
+ env.dispose()
+ }
+ }
+
+ /**
+ * Load all the java source files into [classes].
+ */
+ private fun loadSources() {
+ val env = createUastEnvironment()
+ try {
+ val loader = SourceLoader(env)
+ loader.load(sourceFilesOrDirectories, classes)
+ } finally {
+ env.dispose()
+ }
+ }
+
+ private fun addToAnnotationsAllowedListFile() {
+ log.i("Generating operations to update annotation allowlist file...")
+ log.withIndent {
+ annotationNeedingClasses.sorted().forEach { className ->
+ if (!annotationAllowedClasses.matches(className.toJvmClassName())) {
+ resultOperations.add(
+ SourceOperation(
+ annotationAllowedClassesFile!!,
+ -1, // add to the end
+ SourceOperationType.Insert,
+ className,
+ "add to annotation allowlist"
+ ))
+ }
+ }
+ }
+ }
+
+ /**
+ * Process the policy files with [Processor].
+ */
+ private fun processPolicies() {
+ log.i("Loading the policy files and generating operations...")
+ log.withIndent {
+ policyFiles.forEach { policyFile ->
+ log.i("Parsing $policyFile ...")
+ log.withIndent {
+ policyParser.parse(FileReader(policyFile), policyFile, Processor())
+ }
+ }
+ }
+ }
+
+ private inner class Processor : PolicyFileProcessor {
+
+ var classPolicyText = ""
+ var classPolicyLine = -1
+
+ // Whether the current class has a skip marker, in which case we ignore all members.
+ // Applicable only within a "simple class"
+ var classSkipping = false
+
+ var classLineConverted = false
+ var classHasMember = false
+
+ private fun currentLineHasSkipMarker(): Boolean {
+ val ret = policyParser.currentLineText.contains("no-pta")
+
+ if (ret) {
+ log.forVerbose {
+ log.v("Current line has a skip marker: ${policyParser.currentLineText}")
+ }
+ }
+
+ return ret
+ }
+
+ private fun shouldSkipCurrentLine(): Boolean {
+ // If a line contains a special marker "no-pta", we'll skip it.
+ return classSkipping || currentLineHasSkipMarker()
+ }
+
+ /** Print a warning about an unsupported policy directive. */
+ private fun warnOnPolicy(message: String, policyLine: String, lineNumber: Int) {
+ log.w("Warning: $message")
+ log.w(" policy: \"$policyLine\"")
+ log.w(" at ${policyParser.filename}:$lineNumber")
+ }
+
+ /** Print a warning about an unsupported policy directive. */
+ private fun warnOnCurrentPolicy(message: String) {
+ warnOnPolicy(message, policyParser.currentLineText, policyParser.lineNumber)
+ }
+
+ /** Print a warning about an unsupported policy directive on the class line. */
+ private fun warnOnClassPolicy(message: String) {
+ warnOnPolicy(message, classPolicyText, classPolicyLine)
+ }
+
+ override fun onPackage(name: String, policy: FilterPolicyWithReason) {
+ warnOnCurrentPolicy("'package' directive isn't supported (yet).")
+ }
+
+ override fun onRename(pattern: Pattern, prefix: String) {
+ // Rename will never be supported, so don't show a warning.
+ }
+
+ private fun addOperation(op: SourceOperation) {
+ resultOperations.add(op)
+ }
+
+ private fun commentOutPolicy(lineNumber: Int, description: String) {
+ addOperation(
+ SourceOperation(
+ policyParser.filename,
+ lineNumber,
+ SourceOperationType.Prepend,
+ "#[PTA]: ", // comment out.
+ description,
+ )
+ )
+ }
+
+ override fun onClassStart(className: String) {
+ classSkipping = currentLineHasSkipMarker()
+ classLineConverted = false
+ classHasMember = false
+ classPolicyLine = policyParser.lineNumber
+ classPolicyText = policyParser.currentLineText
+ }
+
+ override fun onClassEnd(className: String) {
+ if (classSkipping) {
+ classSkipping = false
+ return
+ }
+ if (!classLineConverted) {
+ // Class line is still needed in the policy file.
+ // (Because the source file wasn't found.)
+ return
+ }
+ if (!classHasMember) {
+ commentOutPolicy(classPolicyLine, "remove class policy on $className")
+ } else {
+ warnOnClassPolicy(
+ "Class policy on $className can't be removed because it still has members.")
+ }
+ }
+
+ private fun findClass(className: String): ClassInfo? {
+ val ci = classes.findClass(className)
+ if (ci == null) {
+ warnOnCurrentPolicy("Class not found: $className")
+ }
+ return ci
+ }
+
+ private fun addClassAnnotation(
+ className: String,
+ annotation: String,
+ ): Boolean {
+ val ci = findClass(className) ?: return false
+
+ // Add the annotation to the source file.
+ addOperation(
+ SourceOperation(
+ ci.location.file,
+ ci.location.line,
+ SourceOperationType.Insert,
+ ci.location.getIndent() + annotation,
+ "add class annotation to $className"
+ )
+ )
+ annotationNeedingClasses.add(className)
+ return true
+ }
+
+ override fun onSimpleClassPolicy(className: String, policy: FilterPolicyWithReason) {
+ if (shouldSkipCurrentLine()) {
+ return
+ }
+ log.v("Found simple class policy: $className - ${policy.policy}")
+
+ val annot = annotations.get(policy.policy, Annotations.Target.Class)!!
+ if (addClassAnnotation(className, annot)) {
+ classLineConverted = true
+ }
+ }
+
+ override fun onSubClassPolicy(superClassName: String, policy: FilterPolicyWithReason) {
+ warnOnCurrentPolicy("Subclass policies isn't supported (yet).")
+ }
+
+ override fun onRedirectionClass(fromClassName: String, toClassName: String) {
+ if (shouldSkipCurrentLine()) {
+ return
+ }
+
+ log.v("Found class redirection: $fromClassName - $toClassName")
+
+ if (addClassAnnotation(
+ fromClassName,
+ annotations.getRedirectionClassAnnotation(toClassName),
+ )) {
+ commentOutPolicy(policyParser.lineNumber,
+ "remove class redirection policy on $fromClassName")
+ }
+ }
+
+ override fun onClassLoadHook(className: String, callback: String) {
+ if (shouldSkipCurrentLine()) {
+ return
+ }
+
+ log.v("Found class load hook: $className - $callback")
+
+ if (addClassAnnotation(
+ className,
+ annotations.getClassLoadHookAnnotation(callback),
+ )) {
+ commentOutPolicy(policyParser.lineNumber,
+ "remove class load hook policy on $className")
+ }
+ }
+
+ override fun onSpecialClassPolicy(type: SpecialClass, policy: FilterPolicyWithReason) {
+ // This can't be converted to an annotation, so don't show a warning.
+ }
+
+ override fun onField(className: String, fieldName: String, policy: FilterPolicyWithReason) {
+ if (shouldSkipCurrentLine()) {
+ return
+ }
+
+ log.v("Found field policy: $className.$fieldName - ${policy.policy}")
+
+ val ci = findClass(className) ?: return
+
+ ci.findField(fieldName)?.let { fi ->
+ val annot = annotations.get(policy.policy, Annotations.Target.Field)!!
+
+ addOperation(
+ SourceOperation(
+ fi.location.file,
+ fi.location.line,
+ SourceOperationType.Insert,
+ fi.location.getIndent() + annot,
+ "add annotation to field $className.$fieldName",
+ )
+ )
+ commentOutPolicy(policyParser.lineNumber,
+ "remove field policy $className.$fieldName")
+
+ annotationNeedingClasses.add(className)
+ } ?: {
+ warnOnCurrentPolicy("Field not found: $className.$fieldName")
+ }
+ }
+
+ override fun onSimpleMethodPolicy(
+ className: String,
+ methodName: String,
+ methodDesc: String,
+ policy: FilterPolicyWithReason
+ ) {
+ if (shouldSkipCurrentLine()) {
+ return
+ }
+ val readableName = "$className.$methodName$methodDesc"
+ log.v("Found simple method policy: $readableName - ${policy.policy}")
+
+
+ // Inner method to get the matching methods for this policy.
+ //
+ // If this policy can't be converted for any reason, it'll return null.
+ // Otherwise, it'll return a pair of method list and the annotation string.
+ fun getMethods(): Pair<List<MethodInfo>, String>? {
+ if (methodName == CLASS_INITIALIZER_NAME) {
+ warnOnClassPolicy("Policy for class initializers not supported.")
+ return null
+ }
+ val ci = findClass(className) ?: return null
+ val methods = ci.findMethods(methodName, methodDesc)
+ if (methods == null) {
+ warnOnCurrentPolicy("Method not found: $readableName")
+ return null
+ }
+
+ // If the policy is "ignore", we can't convert it to an annotation, in which case
+ // annotations.get() will return null.
+ val annot = annotations.get(policy.policy, Annotations.Target.Method)
+ if (annot == null) {
+ warnOnCurrentPolicy("Annotation for policy '${policy.policy}' isn't available")
+ return null
+ }
+ return Pair(methods, annot)
+ }
+
+ val methodsAndAnnot = getMethods()
+
+ if (methodsAndAnnot == null) {
+ classHasMember = true
+ return // This policy can't converted.
+ }
+ val methods = methodsAndAnnot.first
+ val annot = methodsAndAnnot.second
+
+ var found = false
+ methods.forEach { mi ->
+ found = true
+ addOperation(
+ SourceOperation(
+ mi.location.file,
+ mi.location.line,
+ SourceOperationType.Insert,
+ mi.location.getIndent() + annot,
+ "add annotation to method $readableName",
+ )
+ )
+ }
+ if (found) {
+ commentOutPolicy(
+ policyParser.lineNumber,
+ "remove method policy $readableName"
+ )
+
+ annotationNeedingClasses.add(className)
+ } else {
+ warnOnCurrentPolicy("Method not found: $readableName")
+ }
+ }
+
+ override fun onMethodInClassReplace(
+ className: String,
+ methodName: String,
+ methodDesc: String,
+ targetName: String,
+ policy: FilterPolicyWithReason
+ ) {
+ warnOnCurrentPolicy("Found method replace but it's not supported yet: "
+ + "$className.$methodName$methodDesc - $targetName")
+ }
+
+ override fun onMethodOutClassReplace(
+ className: String,
+ methodName: String,
+ methodDesc: String,
+ replaceSpec: TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec,
+ policy: FilterPolicyWithReason
+ ) {
+ // This can't be converted to an annotation.
+ classHasMember = true
+ }
+ }
+} \ No newline at end of file
diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/psi/PsiUtil.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/psi/PsiUtil.kt
new file mode 100644
index 000000000000..6775135e1ac5
--- /dev/null
+++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/psi/PsiUtil.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.platform.test.ravenwood.ravenhelper.psi
+
+import com.android.tools.lint.UastEnvironment
+
+// PSI is a library to parse Java/Kotlin source files, which is part of JetBrains' IntelliJ/
+// Android Studio, and other IDEs.
+//
+// PSI is normally used by IntelliJ's plugins, and as such, there isn't really a good documentation
+// on how to use it from a standalone program. However, fortunately, Android Studio's Lint
+// and Metalava both use PSI. Metalava reuses some of the APIs exposed by Lint. We also use the
+// same Lint APIs used by Metalava here.
+//
+// Some code pointers around the relevant projects:
+//
+// - We stole code from Metalava, but the recent version of Metalava is too complicated,
+// and hard to understand. Older Metalava, such as this one:
+// https://android.git.corp.google.com/platform/tools/metalava/+/refs/heads/android13-dev
+// is easier to understand.
+//
+// - PSI is source code is available in IntelliJ's code base:
+// https://github.com/JetBrains/intellij-community.git
+//
+// - Lint is in Android studio.
+// https://android.googlesource.com/platform/tools/base/+/studio-master-dev/source.md
+
+
+/**
+ * Create [UastEnvironment] enough to parse Java source files.
+ */
+fun createUastEnvironment(): UastEnvironment {
+ val config = UastEnvironment.Configuration.create(
+ enableKotlinScripting = false,
+ useFirUast = false,
+ )
+
+ config.javaLanguageLevel = com.intellij.pom.java.LanguageLevel.JDK_21
+
+ // The following code exists in Metalava, but we don't seem to need it.
+ // We may need to when we need to support kotlin.
+// config.kotlinLanguageLevel = kotlinLanguageLevel
+// config.addSourceRoots(listOf(File(root)))
+// config.addClasspathRoots(classpath.map { it.absoluteFile })
+// options.jdkHome?.let {
+// if (options.isJdkModular(it)) {
+// config.kotlinCompilerConfig.put(JVMConfigurationKeys.JDK_HOME, it)
+// config.kotlinCompilerConfig.put(JVMConfigurationKeys.NO_JDK, false)
+// }
+// }
+
+ return UastEnvironment.create(config)
+}
diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/SourceMapGenerator.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/SourceMapGenerator.kt
new file mode 100644
index 000000000000..58e4497f9f9c
--- /dev/null
+++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/SourceMapGenerator.kt
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.platform.test.ravenwood.ravenhelper.sourcemap
+
+/*
+ * This file contains classes used to parse Java source files to build "source map" which
+ * basically tells you what classes/methods/fields are declared in what line of what file.
+ */
+
+import com.android.hoststubgen.GeneralUserErrorException
+import com.android.hoststubgen.log
+import com.android.tools.lint.UastEnvironment
+import com.intellij.openapi.editor.Document
+import com.intellij.openapi.vfs.StandardFileSystems
+import com.intellij.psi.PsiClass
+import com.intellij.psi.PsiClassOwner
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiFile
+import com.intellij.psi.PsiManager
+import com.intellij.psi.PsiMethod
+import com.intellij.psi.PsiNameIdentifierOwner
+import com.intellij.psi.SyntheticElement
+import java.io.File
+
+
+/**
+ * Represents the location of an item. (class, field or method)
+ */
+data class Location (
+ /** Full path filename. */
+ val file: String,
+
+ /** 1-based line number */
+ val line: Int,
+
+ /** Indent of the line */
+ val indent: Int,
+) {
+
+ fun getIndent(): String {
+ return " ".repeat(indent)
+ }
+
+ fun dump() {
+ log.i("Location: $file:$line (indent: $indent)")
+ }
+}
+
+/**
+ * Represents the type of item.
+ */
+enum class ItemType {
+ Class,
+ Field,
+ Method,
+}
+
+/** Holds a field's location. */
+data class FieldInfo (
+ val name: String,
+ val location: Location,
+) {
+ fun dump() {
+ log.i("Field: $name")
+ log.withIndent {
+ location.dump()
+ }
+ }
+}
+
+/** Holds a method's location. */
+data class MethodInfo (
+ val name: String,
+ /** "Simplified" description. */
+ val simpleDesc: String,
+ val location: Location,
+) {
+ fun dump() {
+ log.i("Method: $name$simpleDesc")
+ log.withIndent {
+ location.dump()
+ }
+ }
+}
+
+/** Holds a class's location and members. */
+data class ClassInfo (
+ val fullName: String,
+ val location: Location,
+ val fields: MutableMap<String, FieldInfo> = mutableMapOf(),
+ val methods: MutableMap<String, MutableList<MethodInfo>> = mutableMapOf(),
+) {
+ fun add(fi: FieldInfo) {
+ fields.put(fi.name, fi)
+ }
+
+ fun add(mi: MethodInfo) {
+ val list = methods.get(mi.name)
+ if (list != null) {
+ list.add(mi)
+ } else {
+ methods.put(mi.name, mutableListOf(mi))
+ }
+ }
+
+ fun dump() {
+ log.i("Class: $fullName")
+ log.withIndent {
+ location.dump()
+
+ // Sort and print fields and methods.
+ methods.toSortedMap().forEach { entry ->
+ entry.value.sortedBy { method -> method.simpleDesc }.forEach {
+ it.dump()
+ }
+ }
+ }
+ }
+
+ /** Find a field by name */
+ fun findField(fieldName: String): FieldInfo? {
+ return fields[fieldName]
+ }
+
+ /**
+ * Find a field by name and descriptor.
+ *
+ * If [descriptor] is "*", then all methods with the name will be returned.
+ */
+ fun findMethods(methodName: String, methodDesc: String): List<MethodInfo>? {
+ val list = methods[methodName] ?: return null
+
+ // Wildcard method policy.
+ if (methodDesc == "*") {
+ return list
+ }
+
+ val simpleDesc = simplifyMethodDesc(methodDesc)
+ list.forEach { mi ->
+ if (simpleDesc == mi.simpleDesc) {
+ return listOf(mi)
+ }
+ }
+ log.w("Method $fullName.$methodName found, but none match description '$methodDesc'")
+ return null
+ }
+}
+
+/**
+ * Stores all classes
+ */
+data class AllClassInfo (
+ val classes: MutableMap<String, ClassInfo> = mutableMapOf(),
+) {
+ fun add(ci: ClassInfo) {
+ classes.put(ci.fullName, ci)
+ }
+
+ fun dump() {
+ classes.toSortedMap { a, b -> a.compareTo(b) }.forEach {
+ it.value.dump()
+ }
+ }
+
+ fun findClass(name: String): ClassInfo? {
+ return classes.get(name)
+ }
+}
+
+fun typeToSimpleDesc(origType: String): String {
+ var type = origType
+
+ // Detect arrays.
+ var arrayPrefix = ""
+ while (type.endsWith("[]")) {
+ arrayPrefix += "["
+ type = type.substring(0, type.length - 2)
+ }
+
+ // Delete generic parameters. (delete everything after '<')
+ type.indexOf('<').let { pos ->
+ if (pos >= 0) {
+ type = type.substring(0, pos)
+ }
+ }
+
+ // Handle builtins.
+ val builtinType = when (type) {
+ "byte" -> "B"
+ "short" -> "S"
+ "int" -> "I"
+ "long" -> "J"
+ "float" -> "F"
+ "double" -> "D"
+ "boolean" -> "Z"
+ "char" -> "C"
+ "void" -> "V"
+ else -> null
+ }
+
+ builtinType?.let {
+ return arrayPrefix + builtinType
+ }
+
+ return arrayPrefix + "L" + type + ";"
+}
+
+/**
+ * Get a "simple" description of a method.
+ *
+ * "Simple" descriptions are similar to "real" ones, except:
+ * - No return type.
+ * - No package names in type names.
+ */
+fun getSimpleDesc(method: PsiMethod): String {
+ val sb = StringBuilder()
+
+ sb.append("(")
+
+ val params = method.parameterList
+ for (i in 0..<params.parametersCount) {
+ val param = params.getParameter(i)
+
+ val type = param?.type?.presentableText
+
+ if (type == null) {
+ throw RuntimeException(
+ "Unable to decode parameter list from method from ${params.parent}")
+ }
+
+ sb.append(typeToSimpleDesc(type))
+ }
+
+ sb.append(")")
+
+ return sb.toString()
+}
+
+private val reTypeFinder = "L.*/".toRegex()
+
+private fun simplifyMethodDesc(origMethodDesc: String): String {
+ // We don't need the return type, so remove everything after the ')'.
+ val pos = origMethodDesc.indexOf(')')
+ var desc = if (pos < 0) { origMethodDesc } else { origMethodDesc.substring(0, pos + 1) }
+
+ // Then we remove the package names from all the class names.
+ // i.e. convert "Ljava/lang/String" to "LString".
+
+ return desc.replace(reTypeFinder, "L")
+}
+
+/**
+ * Class that reads and parses java source files using PSI and populate [AllClassInfo].
+ */
+class SourceLoader(
+ val environment: UastEnvironment,
+) {
+ private val fileSystem = StandardFileSystems.local()
+ private val manager = PsiManager.getInstance(environment.ideaProject)
+
+ /** Classes that were parsed */
+ private var numParsedClasses = 0
+
+ /**
+ * Main entry point.
+ */
+ fun load(filesOrDirectories: List<String>, classes: AllClassInfo) {
+ val psiFiles = mutableListOf<PsiFile>()
+ log.i("Loading source files...")
+ log.iTime("Discovering source files") {
+ load(filesOrDirectories.map { File(it) }, psiFiles)
+ }
+
+ log.i("${psiFiles.size} file(s) found.")
+
+ if (psiFiles.size == 0) {
+ throw GeneralUserErrorException("No source files found.")
+ }
+
+ log.iTime("Parsing source files") {
+ log.withIndent {
+ for (file in psiFiles.asSequence().distinct()) {
+ val classesInFile = (file as? PsiClassOwner)?.classes?.toList()
+ classesInFile?.forEach { clazz ->
+ loadClass(clazz)?.let { classes.add(it) }
+
+ clazz.innerClasses.forEach { inner ->
+ loadClass(inner)?.let { classes.add(it) }
+ }
+ }
+ }
+ }
+ }
+ log.i("$numParsedClasses class(es) found.")
+ }
+
+ private fun load(filesOrDirectories: List<File>, result: MutableList<PsiFile>) {
+ filesOrDirectories.forEach {
+ load(it, result)
+ }
+ }
+
+ private fun load(file: File, result: MutableList<PsiFile>) {
+ if (file.isDirectory) {
+ file.listFiles()?.forEach { child ->
+ load(child, result)
+ }
+ return
+ }
+
+ // It's a file
+ when (file.extension) {
+ "java" -> {
+ // Load it.
+ }
+ "kt" -> {
+ log.w("Kotlin not supported, not loading ${file.path}")
+ return
+ }
+ else -> return // Silently skip
+ }
+ fileSystem.findFileByPath(file.path)?.let { virtualFile ->
+ manager.findFile(virtualFile)?.let { psiFile ->
+ result.add(psiFile)
+ }
+ }
+ }
+
+ private fun loadClass(clazz: PsiClass): ClassInfo? {
+ if (clazz is SyntheticElement) {
+ return null
+ }
+ log.forVerbose {
+ log.v("Class found: ${clazz.qualifiedName}")
+ }
+ numParsedClasses++
+
+ log.withIndent {
+ val ci = ClassInfo(
+ clazz.qualifiedName!!,
+ getLocation(clazz) ?: return null,
+ )
+
+ // Load fields.
+ clazz.fields.filter { it !is SyntheticElement }.forEach {
+ val name = it.name
+ log.forDebug { log.d("Field found: $name") }
+ val loc = getLocation(it) ?: return@forEach
+ ci.add(FieldInfo(name, loc))
+ }
+
+ // Load methods.
+ clazz.methods.filter { it !is SyntheticElement }.forEach {
+ val name = resolveMethodName(it)
+ val simpleDesc = getSimpleDesc(it)
+ log.forDebug { log.d("Method found: $name$simpleDesc") }
+ val loc = getLocation(it) ?: return@forEach
+ ci.add(MethodInfo(name, simpleDesc, loc))
+ }
+ return ci
+ }
+ }
+
+ private fun resolveMethodName(method: PsiMethod): String {
+ val clazz = method.containingClass!!
+ if (clazz.name == method.name) {
+ return "<init>" // It's a constructor.
+ }
+ return method.name
+ }
+
+ private fun getLocation(elem: PsiElement): Location? {
+ val lineAndIndent = getLineNumberAndIndent(elem)
+ if (lineAndIndent == null) {
+ log.w("Unable to determine location of $elem")
+ return null
+ }
+ return Location(
+ elem.containingFile.originalFile.virtualFile.path,
+ lineAndIndent.first,
+ lineAndIndent.second,
+ )
+ }
+
+ private fun getLineNumberAndIndent(element: PsiElement): Pair<Int, Int>? {
+ val psiFile: PsiFile = element.containingFile ?: return null
+ val document: Document = psiFile.viewProvider.document ?: return null
+
+ // Actual elements such as PsiClass, PsiMethod and PsiField contains the leading
+ // javadoc, etc, so use the "identifier"'s element, if available.
+ // For synthesized elements, this may return null.
+ val targetRange = (
+ (element as PsiNameIdentifierOwner).nameIdentifier?.textRange ?: element.textRange
+ ) ?: return null
+ val lineNumber = document.getLineNumber(targetRange.startOffset)
+ val lineStartOffset = document.getLineStartOffset(lineNumber)
+
+ val lineLeadingText = document.getText(
+ com.intellij.openapi.util.TextRange(lineStartOffset, targetRange.startOffset))
+
+ val indent = lineLeadingText.takeWhile { it.isWhitespace() }.length
+
+ // Line numbers are 0-based, add 1 for human-readable format
+ return Pair(lineNumber + 1, indent)
+ }
+} \ No newline at end of file
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 79888b051c54..70c4c1311fc9 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -21,14 +21,14 @@ import static android.view.MotionEvent.ACTION_SCROLL;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
+import static com.android.hardware.input.Flags.enableTalkbackAndMagnifierKeyGestures;
+
import android.accessibilityservice.AccessibilityTrace;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.content.Context;
import android.graphics.Region;
import android.hardware.input.InputManager;
-import android.hardware.input.KeyGestureEvent;
-import android.os.IBinder;
import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemClock;
@@ -46,15 +46,13 @@ import android.view.MotionEvent.PointerCoords;
import android.view.MotionEvent.PointerProperties;
import android.view.accessibility.AccessibilityEvent;
-import androidx.annotation.Nullable;
-
import com.android.server.LocalServices;
import com.android.server.accessibility.gestures.TouchExplorer;
import com.android.server.accessibility.magnification.FullScreenMagnificationController;
import com.android.server.accessibility.magnification.FullScreenMagnificationGestureHandler;
import com.android.server.accessibility.magnification.FullScreenMagnificationVibrationHelper;
-import com.android.server.accessibility.magnification.MagnificationController;
import com.android.server.accessibility.magnification.MagnificationGestureHandler;
+import com.android.server.accessibility.magnification.MagnificationKeyHandler;
import com.android.server.accessibility.magnification.MouseEventHandler;
import com.android.server.accessibility.magnification.WindowMagnificationGestureHandler;
import com.android.server.accessibility.magnification.WindowMagnificationPromptController;
@@ -209,6 +207,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
private MouseKeysInterceptor mMouseKeysInterceptor;
+ private MagnificationKeyHandler mMagnificationKeyHandler;
+
private boolean mInstalled;
private int mUserId;
@@ -235,74 +235,6 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
*/
private MotionEvent mLastActiveDeviceMotionEvent = null;
- private boolean mKeyGestureEventHandlerInstalled = false;
- private InputManager.KeyGestureEventHandler mKeyGestureEventHandler =
- new InputManager.KeyGestureEventHandler() {
- @Override
- public boolean handleKeyGestureEvent(
- @NonNull KeyGestureEvent event,
- @Nullable IBinder focusedToken) {
- final boolean complete =
- event.getAction() == KeyGestureEvent.ACTION_GESTURE_COMPLETE
- && !event.isCancelled();
-
- // TODO(b/355499907): Receive and handle held key gestures, which can be used
- // for continuous scaling and panning. In addition, handle multiple pan gestures
- // at the same time (e.g. user may try to pan diagonally) reasonably, including
- // decreasing diagonal movement by sqrt(2) to make it appear the same speed
- // as non-diagonal movement.
-
- if (!complete) {
- return false;
- }
-
- final int gestureType = event.getKeyGestureType();
- final int displayId = isDisplayIdValid(event.getDisplayId())
- ? event.getDisplayId() : Display.DEFAULT_DISPLAY;
-
- switch (gestureType) {
- case KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_ZOOM_IN:
- mAms.getMagnificationController().scaleMagnificationByStep(
- displayId, MagnificationController.ZOOM_DIRECTION_IN);
- return true;
- case KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_ZOOM_OUT:
- mAms.getMagnificationController().scaleMagnificationByStep(
- displayId, MagnificationController.ZOOM_DIRECTION_OUT);
- return true;
- case KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_PAN_LEFT:
- mAms.getMagnificationController().panMagnificationByStep(
- displayId, MagnificationController.PAN_DIRECTION_LEFT);
- return true;
- case KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_PAN_RIGHT:
- mAms.getMagnificationController().panMagnificationByStep(
- displayId, MagnificationController.PAN_DIRECTION_RIGHT);
- return true;
- case KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_PAN_UP:
- mAms.getMagnificationController().panMagnificationByStep(
- displayId, MagnificationController.PAN_DIRECTION_UP);
- return true;
- case KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_PAN_DOWN:
- mAms.getMagnificationController().panMagnificationByStep(
- displayId, MagnificationController.PAN_DIRECTION_DOWN);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean isKeyGestureSupported(int gestureType) {
- return switch (gestureType) {
- case KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_ZOOM_IN,
- KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_ZOOM_OUT,
- KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_PAN_LEFT,
- KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_PAN_RIGHT,
- KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_PAN_UP,
- KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_PAN_DOWN -> true;
- default -> false;
- };
- }
- };
-
private static MotionEvent cancelMotion(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_CANCEL
|| event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT
@@ -787,20 +719,11 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
});
}
- if ((mEnabledFeatures & FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER) != 0
- || ((mEnabledFeatures & FLAG_FEATURE_MAGNIFICATION_SINGLE_FINGER_TRIPLE_TAP) != 0)
- || ((mEnabledFeatures & FLAG_FEATURE_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP) != 0)
- || ((mEnabledFeatures & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0)) {
+ if (isAnyMagnificationEnabled()) {
final MagnificationGestureHandler magnificationGestureHandler =
createMagnificationGestureHandler(displayId, displayContext);
addFirstEventHandler(displayId, magnificationGestureHandler);
mMagnificationGestureHandler.put(displayId, magnificationGestureHandler);
-
- if (com.android.hardware.input.Flags.enableTalkbackAndMagnifierKeyGestures()
- && !mKeyGestureEventHandlerInstalled) {
- mInputManager.registerKeyGestureEventHandler(mKeyGestureEventHandler);
- mKeyGestureEventHandlerInstalled = true;
- }
}
if ((mEnabledFeatures & FLAG_FEATURE_INJECT_MOTION_EVENTS) != 0) {
@@ -817,6 +740,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
}
if ((mEnabledFeatures & FLAG_FEATURE_FILTER_KEY_EVENTS) != 0) {
+ // mKeyboardInterceptor does not forward KeyEvents to other EventStreamTransformations,
+ // so it must be the last EventStreamTransformation for key events in the list.
mKeyboardInterceptor = new KeyboardInterceptor(mAms,
LocalServices.getService(WindowManagerPolicy.class));
// Since the display id of KeyEvent always would be -1 and it would be dispatched to
@@ -832,6 +757,19 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
Display.DEFAULT_DISPLAY);
addFirstEventHandler(Display.DEFAULT_DISPLAY, mMouseKeysInterceptor);
}
+
+ if (enableTalkbackAndMagnifierKeyGestures() && isAnyMagnificationEnabled()) {
+ mMagnificationKeyHandler = new MagnificationKeyHandler(
+ mAms.getMagnificationController());
+ addFirstEventHandler(Display.DEFAULT_DISPLAY, mMagnificationKeyHandler);
+ }
+ }
+
+ private boolean isAnyMagnificationEnabled() {
+ return (mEnabledFeatures & FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER) != 0
+ || ((mEnabledFeatures & FLAG_FEATURE_MAGNIFICATION_SINGLE_FINGER_TRIPLE_TAP) != 0)
+ || ((mEnabledFeatures & FLAG_FEATURE_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP) != 0)
+ || ((mEnabledFeatures & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0);
}
/**
@@ -921,9 +859,9 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
mMouseKeysInterceptor = null;
}
- if (mKeyGestureEventHandlerInstalled) {
- mInputManager.unregisterKeyGestureEventHandler(mKeyGestureEventHandler);
- mKeyGestureEventHandlerInstalled = false;
+ if (mMagnificationKeyHandler != null) {
+ mMagnificationKeyHandler.onDestroy();
+ mMagnificationKeyHandler = null;
}
}
@@ -1365,6 +1303,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
joiner.add("AutoclickController");
} else if (next instanceof MotionEventInjector) {
joiner.add("MotionEventInjector");
+ } else if (next instanceof MagnificationKeyHandler) {
+ joiner.add("MagnificationKeyHandler");
}
next = next.getNext();
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 8e037c3ba90c..875b655fe3d2 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -35,8 +35,6 @@ import static android.accessibilityservice.AccessibilityTrace.FLAGS_MAGNIFICATIO
import static android.accessibilityservice.AccessibilityTrace.FLAGS_PACKAGE_BROADCAST_RECEIVER;
import static android.accessibilityservice.AccessibilityTrace.FLAGS_USER_BROADCAST_RECEIVER;
import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL;
-import static android.companion.virtual.VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED;
-import static android.companion.virtual.VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID;
import static android.content.Context.DEVICE_ID_DEFAULT;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE;
@@ -1116,22 +1114,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mContext.registerReceiverAsUser(
receiver, UserHandle.ALL, filter, null, mMainHandler,
Context.RECEIVER_EXPORTED);
-
- if (!android.companion.virtual.flags.Flags.vdmPublicApis()) {
- final BroadcastReceiver virtualDeviceReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final int deviceId = intent.getIntExtra(
- EXTRA_VIRTUAL_DEVICE_ID, DEVICE_ID_DEFAULT);
- mProxyManager.clearConnections(deviceId);
- }
- };
-
- final IntentFilter virtualDeviceFilter = new IntentFilter(
- ACTION_VIRTUAL_DEVICE_REMOVED);
- mContext.registerReceiver(virtualDeviceReceiver, virtualDeviceFilter,
- Context.RECEIVER_NOT_EXPORTED);
- }
}
/**
@@ -1841,9 +1823,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
public void notifyQuickSettingsTilesChanged(
@UserIdInt int userId, @NonNull List<ComponentName> tileComponentNames) {
notifyQuickSettingsTilesChanged_enforcePermission();
- if (!android.view.accessibility.Flags.a11yQsShortcut()) {
- return;
- }
if (DEBUG) {
Slog.d(LOG_TAG, TextUtils.formatSimple(
"notifyQuickSettingsTilesChanged userId: %d, tileComponentNames: %s",
@@ -2278,9 +2257,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private void restoreShortcutTargets(
String newValue, @UserShortcutType int shortcutType, int userId) {
assertNoTapShortcut(shortcutType);
- if (shortcutType == QUICK_SETTINGS && !android.view.accessibility.Flags.a11yQsShortcut()) {
- return;
- }
synchronized (mLock) {
final AccessibilityUserState userState = getUserStateLocked(userId);
@@ -3894,9 +3870,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
*/
private void updateAccessibilityShortcutTargetsLocked(
AccessibilityUserState userState, @UserShortcutType int shortcutType) {
- if (shortcutType == QUICK_SETTINGS && !android.view.accessibility.Flags.a11yQsShortcut()) {
- return;
- }
if (shortcutType == SOFTWARE) {
// Update accessibility button availability.
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
@@ -4079,9 +4052,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
final List<Integer> shortcutTypes = new ArrayList<>(4);
shortcutTypes.add(HARDWARE);
shortcutTypes.add(SOFTWARE);
- if (android.view.accessibility.Flags.a11yQsShortcut()) {
- shortcutTypes.add(QUICK_SETTINGS);
- }
+ shortcutTypes.add(QUICK_SETTINGS);
if (android.provider.Flags.a11yStandaloneGestureEnabled()) {
shortcutTypes.add(GESTURE);
}
@@ -4385,13 +4356,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private void launchAccessibilityFrameworkFeature(int displayId, ComponentName assignedTarget) {
if (assignedTarget.equals(ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME)) {
- //import com.android.systemui.Flags;
- if (com.android.systemui.Flags.hearingAidsQsTileDialog()) {
- launchHearingDevicesDialog();
- } else {
- launchAccessibilitySubSettings(displayId,
- ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME);
- }
+ launchHearingDevicesDialog();
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
index f8551457d04d..8adee24c7143 100644
--- a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
@@ -217,7 +217,7 @@ public class ProxyManager {
private void registerVirtualDeviceListener() {
VirtualDeviceManager vdm = mContext.getSystemService(VirtualDeviceManager.class);
- if (vdm == null || !android.companion.virtual.flags.Flags.vdmPublicApis()) {
+ if (vdm == null) {
return;
}
if (mVirtualDeviceListener == null) {
@@ -234,7 +234,7 @@ public class ProxyManager {
private void unregisterVirtualDeviceListener() {
VirtualDeviceManager vdm = mContext.getSystemService(VirtualDeviceManager.class);
- if (vdm == null || !android.companion.virtual.flags.Flags.vdmPublicApis()) {
+ if (vdm == null) {
return;
}
vdm.unregisterVirtualDeviceListener(mVirtualDeviceListener);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 2e131b696afc..75ec8ea88ace 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -84,7 +84,7 @@ import java.util.concurrent.Executor;
* is done and before invoking {@link TransitionCallBack#onResult}.
*/
public class MagnificationController implements MagnificationConnectionManager.Callback,
- MagnificationGestureHandler.Callback,
+ MagnificationGestureHandler.Callback, MagnificationKeyHandler.Callback,
FullScreenMagnificationController.MagnificationInfoChangedCallback,
WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks {
@@ -347,6 +347,36 @@ public class MagnificationController implements MagnificationConnectionManager.C
handleUserInteractionChanged(displayId, mode);
}
+ @Override
+ public void onPanMagnificationStart(int displayId,
+ @MagnificationController.PanDirection int direction) {
+ // TODO(b/355499907): Handle multiple pan gestures at the same time (e.g. user may try to
+ // pan diagonally) by decreasing diagonal movement by sqrt(2) to make it appear the same
+ // speed as non-diagonal movement.
+ panMagnificationByStep(displayId, direction);
+ }
+
+ @Override
+ public void onPanMagnificationStop(int displayId,
+ @MagnificationController.PanDirection int direction) {
+ // TODO(b/388847283): Handle held key gestures, which can be used
+ // for continuous scaling and panning, until they are released.
+
+ }
+
+ @Override
+ public void onScaleMagnificationStart(int displayId,
+ @MagnificationController.ZoomDirection int direction) {
+ scaleMagnificationByStep(displayId, direction);
+ }
+
+ @Override
+ public void onScaleMagnificationStop(int displayId,
+ @MagnificationController.ZoomDirection int direction) {
+ // TODO(b/388847283): Handle held key gestures, which can be used
+ // for continuous scaling and panning, until they are released.
+ }
+
private void handleUserInteractionChanged(int displayId, int mode) {
if (mMagnificationCapabilities != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) {
return;
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationKeyHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationKeyHandler.java
new file mode 100644
index 000000000000..a65580c82124
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationKeyHandler.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.accessibility.magnification;
+
+import android.view.Display;
+import android.view.KeyEvent;
+
+import com.android.server.accessibility.BaseEventStreamTransformation;
+
+/*
+ * A class that listens to key presses used to control magnification.
+ */
+public class MagnificationKeyHandler extends BaseEventStreamTransformation {
+
+ /** Callback interface to report that a user is intending to interact with Magnification. */
+ public interface Callback {
+ /**
+ * Called when a keyboard shortcut to pan magnification in direction {@code direction} is
+ * pressed by a user. Note that this can be called for multiple directions if multiple
+ * arrows are pressed at the same time (e.g. diagonal panning).
+ *
+ * @param displayId The logical display ID
+ * @param direction The direction to start panning
+ */
+ void onPanMagnificationStart(int displayId,
+ @MagnificationController.PanDirection int direction);
+
+ /**
+ * Called when a keyboard shortcut to pan magnification in direction {@code direction} is
+ * unpressed by a user. Note that this can be called for multiple directions if multiple
+ * arrows had been pressed at the same time (e.g. diagonal panning).
+ *
+ * @param displayId The logical display ID
+ * @param direction The direction in which panning stopped
+ */
+ void onPanMagnificationStop(int displayId,
+ @MagnificationController.PanDirection int direction);
+
+ /**
+ * Called when a keyboard shortcut to scale magnification in direction `direction` is
+ * pressed by a user.
+ *
+ * @param displayId The logical display ID
+ * @param direction The direction in which scaling started
+ */
+ void onScaleMagnificationStart(int displayId,
+ @MagnificationController.ZoomDirection int direction);
+
+ /**
+ * Called when a keyboard shortcut to scale magnification in direction `direction` is
+ * unpressed by a user.
+ *
+ * @param displayId The logical display ID
+ * @param direction The direction in which scaling stopped
+ */
+ void onScaleMagnificationStop(int displayId,
+ @MagnificationController.ZoomDirection int direction);
+ }
+
+ protected final MagnificationKeyHandler.Callback mCallback;
+
+ public MagnificationKeyHandler(Callback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void onKeyEvent(KeyEvent event, int policyFlags) {
+ if (!com.android.hardware.input.Flags.enableTalkbackAndMagnifierKeyGestures()) {
+ // Send to the rest of the handlers.
+ super.onKeyEvent(event, policyFlags);
+ return;
+ }
+ boolean modifiersPressed = event.isAltPressed() && event.isMetaPressed();
+ if (!modifiersPressed) {
+ super.onKeyEvent(event, policyFlags);
+ return;
+ }
+ boolean isDown = event.getAction() == KeyEvent.ACTION_DOWN;
+ int keyCode = event.getKeyCode();
+ if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT
+ || keyCode == KeyEvent.KEYCODE_DPAD_UP || keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
+ int panDirection = switch(keyCode) {
+ case KeyEvent.KEYCODE_DPAD_LEFT -> MagnificationController.PAN_DIRECTION_LEFT;
+ case KeyEvent.KEYCODE_DPAD_RIGHT -> MagnificationController.PAN_DIRECTION_RIGHT;
+ case KeyEvent.KEYCODE_DPAD_UP -> MagnificationController.PAN_DIRECTION_UP;
+ default -> MagnificationController.PAN_DIRECTION_DOWN;
+ };
+ if (isDown) {
+ mCallback.onPanMagnificationStart(getDisplayId(event), panDirection);
+ } else {
+ mCallback.onPanMagnificationStop(getDisplayId(event), panDirection);
+ }
+ return;
+ } else if (keyCode == KeyEvent.KEYCODE_EQUALS || keyCode == KeyEvent.KEYCODE_MINUS) {
+ int zoomDirection = MagnificationController.ZOOM_DIRECTION_OUT;
+ if (keyCode == KeyEvent.KEYCODE_EQUALS) {
+ zoomDirection = MagnificationController.ZOOM_DIRECTION_IN;
+ }
+ if (isDown) {
+ mCallback.onScaleMagnificationStart(getDisplayId(event), zoomDirection);
+ } else {
+ mCallback.onScaleMagnificationStop(getDisplayId(event), zoomDirection);
+ }
+ return;
+ }
+
+ // Continue down the eventing chain if this was unused.
+ super.onKeyEvent(event, policyFlags);
+ }
+
+ private int getDisplayId(KeyEvent event) {
+ // Display ID may be invalid, e.g. for external keyboard attached to phone.
+ // In that case, use the default display.
+ if (event.getDisplayId() != Display.INVALID_DISPLAY) {
+ return event.getDisplayId();
+ }
+ return Display.DEFAULT_DISPLAY;
+ }
+}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 1dba629b9a55..cffdfbd36532 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -5666,13 +5666,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
public boolean canAccessAppWidget(Widget widget, int uid, String packageName) {
- if (isDifferentPackageFromHost(widget.host, packageName)
- && isDifferentPackageFromProvider(widget.provider, packageName)) {
- // Apps providing AppWidget are only allowed to access widgets provided by the
- // same package. Similarly, apps hosting AppWidget are only allowed to access
- // widgets hosted by the same package.
- return false;
- }
if (isHostInPackageForUid(widget.host, uid, packageName)) {
// Apps hosting the AppWidget have access to it.
return true;
@@ -5775,19 +5768,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
&& provider.id.componentName.getPackageName().equals(packageName);
}
- private boolean isDifferentPackageFromHost(
- @Nullable final Host host, @Nullable final String packageName) {
- return packageName == null || host == null || host.id == null
- || !packageName.equals(host.id.packageName);
- }
-
- private boolean isDifferentPackageFromProvider(
- @Nullable final Provider provider, @Nullable final String packageName) {
- return packageName == null || provider == null || provider.id == null
- || provider.id.componentName == null
- || !packageName.equals(provider.id.componentName.getPackageName());
- }
-
private boolean isProfileEnabled(int profileId) {
final long identity = Binder.clearCallingIdentity();
try {
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 5af2346650ed..2143aaaa4cd6 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -236,12 +236,13 @@ public class UserBackupManagerService {
// If an app is busy when we want to do a full-data backup, how long to defer the retry.
// This is fuzzed, so there are two parameters; backoff_min + Rand[0, backoff_fuzz)
- private static final long BUSY_BACKOFF_MIN_MILLIS = 1000 * 60 * 60; // one hour
- private static final int BUSY_BACKOFF_FUZZ = 1000 * 60 * 60 * 2; // two hours
+ private static final long BUSY_BACKOFF_MIN_MILLIS = 1000 * 60 * 60; // one hour
+ private static final int BUSY_BACKOFF_FUZZ = 1000 * 60 * 60 * 2; // two hours
private static final String SERIAL_ID_FILE = "serial_id";
private final @UserIdInt int mUserId;
+ private final String mLogIdMsg; // Prepended to Logcat messages.
private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
private final TransportManager mTransportManager;
@@ -259,13 +260,13 @@ public class UserBackupManagerService {
private final IBackupManager mBackupManagerBinder;
- private boolean mEnabled; // writes to this are synchronized on 'this'
+ private boolean mEnabled; // writes to this are synchronized on 'this'
private boolean mSetupComplete;
private boolean mAutoRestore;
private final PendingIntent mRunInitIntent;
- private final ArraySet<String> mPendingInits = new ArraySet<>(); // transport names
+ private final ArraySet<String> mPendingInits = new ArraySet<>(); // transport names
// map UIDs to the set of participating packages under that UID
private final SparseArray<HashSet<String>> mBackupParticipants = new SparseArray<>();
@@ -315,8 +316,7 @@ public class UserBackupManagerService {
private final File mBaseStateDir;
private final File mDataDir;
private final File mJournalDir;
- @Nullable
- private DataChangedJournal mJournal;
+ @Nullable private DataChangedJournal mJournal;
private final File mFullBackupScheduleFile;
// Keep a log of all the apps we've ever backed up.
@@ -337,7 +337,7 @@ public class UserBackupManagerService {
* includes setting up the directories where we keep our bookkeeping and transport management.
*
* @see #createAndInitializeService(int, Context, BackupManagerService, HandlerThread, File,
- * File, TransportManager)
+ * File, TransportManager)
*/
static UserBackupManagerService createAndInitializeService(
@UserIdInt int userId,
@@ -351,7 +351,7 @@ public class UserBackupManagerService {
currentTransport = null;
}
- Slog.d(TAG, addUserIdToLogMessage(userId, "Starting with transport " + currentTransport));
+ Slog.d(TAG, "Starting with transport " + currentTransport + " for user " + userId);
TransportManager transportManager =
new TransportManager(userId, context, transportWhitelist, currentTransport);
@@ -361,7 +361,7 @@ public class UserBackupManagerService {
HandlerThread userBackupThread =
new HandlerThread("backup-" + userId, Process.THREAD_PRIORITY_BACKGROUND);
userBackupThread.start();
- Slog.d(TAG, addUserIdToLogMessage(userId, "Started thread " + userBackupThread.getName()));
+ Slog.d(TAG, "Started thread " + userBackupThread.getName() + " for user " + userId);
return createAndInitializeService(
userId,
@@ -417,26 +417,32 @@ public class UserBackupManagerService {
*/
public static boolean getSetupCompleteSettingForUser(Context context, int userId) {
return Settings.Secure.getIntForUser(
- context.getContentResolver(),
- Settings.Secure.USER_SETUP_COMPLETE,
- 0,
- userId)
+ context.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE,
+ 0,
+ userId)
!= 0;
}
@VisibleForTesting
- UserBackupManagerService(Context context, PackageManager packageManager,
- LifecycleOperationStorage operationStorage, TransportManager transportManager,
- BackupHandler backupHandler, BackupManagerConstants backupManagerConstants,
- IActivityManager activityManager, ActivityManagerInternal activityManagerInternal) {
+ UserBackupManagerService(
+ Context context,
+ PackageManager packageManager,
+ LifecycleOperationStorage operationStorage,
+ TransportManager transportManager,
+ BackupHandler backupHandler,
+ BackupManagerConstants backupManagerConstants,
+ IActivityManager activityManager,
+ ActivityManagerInternal activityManagerInternal) {
mContext = context;
mUserId = 0;
+ mLogIdMsg = "[UserID:" + mUserId + "] ";
mRegisterTransportsRequestedTime = 0;
mPackageManager = packageManager;
mOperationStorage = operationStorage;
- mBackupAgentConnectionManager = new BackupAgentConnectionManager(mOperationStorage,
- mPackageManager, this, mUserId);
+ mBackupAgentConnectionManager =
+ new BackupAgentConnectionManager(mOperationStorage, mPackageManager, this, mUserId);
mTransportManager = transportManager;
mFullBackupQueue = new ArrayList<>();
mBackupHandler = backupHandler;
@@ -470,13 +476,14 @@ public class UserBackupManagerService {
File dataDir,
TransportManager transportManager) {
mUserId = userId;
+ mLogIdMsg = "[UserID:" + mUserId + "] ";
mContext = Objects.requireNonNull(context, "context cannot be null");
mPackageManager = context.getPackageManager();
mPackageManagerBinder = AppGlobals.getPackageManager();
mActivityManager = ActivityManager.getService();
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
- mScheduledBackupEligibility = getEligibilityRules(mPackageManager, userId, mContext,
- BackupDestination.CLOUD);
+ mScheduledBackupEligibility =
+ getEligibilityRules(mPackageManager, userId, mContext, BackupDestination.CLOUD);
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
@@ -484,13 +491,13 @@ public class UserBackupManagerService {
Objects.requireNonNull(parent, "parent cannot be null");
mBackupManagerBinder = BackupManagerService.asInterface(parent.asBinder());
- mAgentTimeoutParameters = new
- BackupAgentTimeoutParameters(Handler.getMain(), mContext.getContentResolver());
+ mAgentTimeoutParameters =
+ new BackupAgentTimeoutParameters(Handler.getMain(), mContext.getContentResolver());
mAgentTimeoutParameters.start();
mOperationStorage = new LifecycleOperationStorage(mUserId);
- mBackupAgentConnectionManager = new BackupAgentConnectionManager(mOperationStorage,
- mPackageManager, this, mUserId);
+ mBackupAgentConnectionManager =
+ new BackupAgentConnectionManager(mOperationStorage, mPackageManager, this, mUserId);
Objects.requireNonNull(userBackupThread, "userBackupThread cannot be null");
mBackupHandler = new BackupHandler(this, mOperationStorage, userBackupThread);
@@ -498,8 +505,10 @@ public class UserBackupManagerService {
// Set up our bookkeeping
final ContentResolver resolver = context.getContentResolver();
mSetupComplete = getSetupCompleteSettingForUser(context, userId);
- mAutoRestore = Settings.Secure.getIntForUser(resolver,
- Settings.Secure.BACKUP_AUTO_RESTORE, 1, userId) != 0;
+ mAutoRestore =
+ Settings.Secure.getIntForUser(
+ resolver, Settings.Secure.BACKUP_AUTO_RESTORE, 1, userId)
+ != 0;
mSetupObserver = new SetupObserver(this, mBackupHandler);
resolver.registerContentObserver(
@@ -514,10 +523,7 @@ public class UserBackupManagerService {
if (userId == UserHandle.USER_SYSTEM) {
mBaseStateDir.mkdirs();
if (!SELinux.restorecon(mBaseStateDir)) {
- Slog.w(
- TAG,
- addUserIdToLogMessage(
- userId, "SELinux restorecon failed on " + mBaseStateDir));
+ Slog.w(TAG, mLogIdMsg + "SELinux restorecon failed on " + mBaseStateDir);
}
}
@@ -549,8 +555,8 @@ public class UserBackupManagerService {
// Set up the backup-request journaling
mJournalDir = new File(mBaseStateDir, "pending");
- mJournalDir.mkdirs(); // creates mBaseStateDir along the way
- mJournal = null; // will be created on first use
+ mJournalDir.mkdirs(); // creates mBaseStateDir along the way
+ mJournal = null; // will be created on first use
mConstants = new BackupManagerConstants(mBackupHandler, mContext.getContentResolver());
// We are observing changes to the constants throughout the lifecycle of BMS. This is
@@ -580,14 +586,20 @@ public class UserBackupManagerService {
// if so delete expired events and do not print them to dumpsys
BackupManagerMonitorDumpsysUtils backupManagerMonitorDumpsysUtils =
new BackupManagerMonitorDumpsysUtils();
- mBackupHandler.postDelayed(backupManagerMonitorDumpsysUtils::deleteExpiredBMMEvents,
+ mBackupHandler.postDelayed(
+ backupManagerMonitorDumpsysUtils::deleteExpiredBMMEvents,
INITIALIZATION_DELAY_MILLIS);
mBackupPreferences = new UserBackupPreferences(mContext, mBaseStateDir);
// Power management
- mWakelock = new BackupWakeLock(mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
- "*backup*-" + userId + "-" + userBackupThread.getThreadId()), userId, mConstants);
+ mWakelock =
+ new BackupWakeLock(
+ mPowerManager.newWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK,
+ "*backup*-" + userId + "-" + userBackupThread.getThreadId()),
+ userId,
+ mConstants);
// Set up the various sorts of package tracking we do
mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule");
@@ -788,14 +800,13 @@ public class UserBackupManagerService {
mPendingInits.clear();
}
- public void setRunningFullBackupTask(
- PerformFullTransportBackupTask runningFullBackupTask) {
+ public void setRunningFullBackupTask(PerformFullTransportBackupTask runningFullBackupTask) {
mRunningFullBackupTask = runningFullBackupTask;
}
/**
- * Utility: build a new random integer token. The low bits are the ordinal of the operation for
- * near-time uniqueness, and the upper bits are random for app-side unpredictability.
+ * Utility: build a new random integer token. The low bits are the ordinal of the operation for
+ * near-time uniqueness, and the upper bits are random for app-side unpredictability.
*/
public int generateRandomIntegerToken() {
int token = mTokenGenerator.nextInt();
@@ -815,16 +826,14 @@ public class UserBackupManagerService {
public BackupAgent makeMetadataAgentWithEligibilityRules(
BackupEligibilityRules backupEligibilityRules) {
- PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(mPackageManager, mUserId,
- backupEligibilityRules);
+ PackageManagerBackupAgent pmAgent =
+ new PackageManagerBackupAgent(mPackageManager, mUserId, backupEligibilityRules);
pmAgent.attach(mContext);
pmAgent.onCreate(UserHandle.of(mUserId));
return pmAgent;
}
- /**
- * Same as {@link #makeMetadataAgent()} but with explicit package-set configuration.
- */
+ /** Same as {@link #makeMetadataAgent()} but with explicit package-set configuration. */
public PackageManagerBackupAgent makeMetadataAgent(List<PackageInfo> packages) {
PackageManagerBackupAgent pmAgent =
new PackageManagerBackupAgent(mPackageManager, packages, mUserId);
@@ -834,12 +843,12 @@ public class UserBackupManagerService {
}
private void initPackageTracking() {
- if (DEBUG) Slog.v(TAG, addUserIdToLogMessage(mUserId, "` tracking"));
+ if (DEBUG) Slog.v(TAG, mLogIdMsg + "` tracking");
// Remember our ancestral dataset
mTokenFile = new File(mBaseStateDir, "ancestral");
- try (DataInputStream tokenStream = new DataInputStream(new BufferedInputStream(
- new FileInputStream(mTokenFile)))) {
+ try (DataInputStream tokenStream =
+ new DataInputStream(new BufferedInputStream(new FileInputStream(mTokenFile)))) {
int version = tokenStream.readInt();
if (version == CURRENT_ANCESTRAL_RECORD_VERSION) {
mAncestralToken = tokenStream.readLong();
@@ -856,9 +865,9 @@ public class UserBackupManagerService {
}
} catch (FileNotFoundException fnf) {
// Probably innocuous
- Slog.d(TAG, addUserIdToLogMessage(mUserId, "No ancestral data"));
+ Slog.d(TAG, mLogIdMsg + "No ancestral data");
} catch (IOException e) {
- Slog.w(TAG, addUserIdToLogMessage(mUserId, "Unable to read token file"), e);
+ Slog.w(TAG, mLogIdMsg + "Unable to read token file", e);
}
mProcessedPackagesJournal = new ProcessedPackagesJournal(mBaseStateDir);
@@ -899,20 +908,20 @@ public class UserBackupManagerService {
boolean changed = false;
ArrayList<FullBackupEntry> schedule = null;
List<PackageInfo> apps =
- PackageManagerBackupAgent.getStorableApplications(mPackageManager, mUserId,
- mScheduledBackupEligibility);
+ PackageManagerBackupAgent.getStorableApplications(
+ mPackageManager, mUserId, mScheduledBackupEligibility);
if (mFullBackupScheduleFile.exists()) {
try (FileInputStream fstream = new FileInputStream(mFullBackupScheduleFile);
- BufferedInputStream bufStream = new BufferedInputStream(fstream);
- DataInputStream in = new DataInputStream(bufStream)) {
+ BufferedInputStream bufStream = new BufferedInputStream(fstream);
+ DataInputStream in = new DataInputStream(bufStream)) {
int version = in.readInt();
if (version != SCHEDULE_FILE_VERSION) {
// The file version doesn't match the expected value.
// Since this is within a "try" block, this exception will be treated like
// any other exception, and caught below.
- throw new IllegalArgumentException("Unknown backup schedule version "
- + version);
+ throw new IllegalArgumentException(
+ "Unknown backup schedule version " + version);
}
final int numPackages = in.readInt();
@@ -935,12 +944,20 @@ public class UserBackupManagerService {
pkg.applicationInfo)) {
schedule.add(new FullBackupEntry(pkgName, lastBackup));
} else {
- Slog.i(TAG, addUserIdToLogMessage(mUserId, "Package " + pkgName
- + " no longer eligible for full backup"));
+ Slog.i(
+ TAG,
+ mLogIdMsg
+ + "Package "
+ + pkgName
+ + " no longer eligible for full backup");
}
} catch (NameNotFoundException e) {
- Slog.i(TAG, addUserIdToLogMessage(mUserId, "Package " + pkgName
- + " not installed; dropping from full backup"));
+ Slog.i(
+ TAG,
+ mLogIdMsg
+ + "Package "
+ + pkgName
+ + " not installed; dropping from full backup");
}
}
@@ -954,11 +971,10 @@ public class UserBackupManagerService {
if (DEBUG) {
Slog.i(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "New full backup app "
- + app.packageName
- + " found"));
+ mLogIdMsg
+ + "New full backup app "
+ + app.packageName
+ + " found");
}
schedule.add(new FullBackupEntry(app.packageName, 0));
changed = true;
@@ -968,7 +984,7 @@ public class UserBackupManagerService {
Collections.sort(schedule);
} catch (Exception e) {
- Slog.e(TAG, addUserIdToLogMessage(mUserId, "Unable to read backup schedule"), e);
+ Slog.e(TAG, mLogIdMsg + "Unable to read backup schedule", e);
mFullBackupScheduleFile.delete();
schedule = null;
}
@@ -994,46 +1010,43 @@ public class UserBackupManagerService {
return schedule;
}
- private Runnable mFullBackupScheduleWriter = new Runnable() {
- @Override
- public void run() {
- synchronized (mQueueLock) {
- try {
- ByteArrayOutputStream bufStream = new ByteArrayOutputStream(4096);
- DataOutputStream bufOut = new DataOutputStream(bufStream);
- bufOut.writeInt(SCHEDULE_FILE_VERSION);
-
- // version 1:
- //
- // [int] # of packages in the queue = N
- // N * {
- // [utf8] package name
- // [long] last backup time for this package
- // }
- int numPackages = mFullBackupQueue.size();
- bufOut.writeInt(numPackages);
-
- for (int i = 0; i < numPackages; i++) {
- FullBackupEntry entry = mFullBackupQueue.get(i);
- bufOut.writeUTF(entry.packageName);
- bufOut.writeLong(entry.lastBackup);
+ private Runnable mFullBackupScheduleWriter =
+ new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mQueueLock) {
+ try {
+ ByteArrayOutputStream bufStream = new ByteArrayOutputStream(4096);
+ DataOutputStream bufOut = new DataOutputStream(bufStream);
+ bufOut.writeInt(SCHEDULE_FILE_VERSION);
+
+ // version 1:
+ //
+ // [int] # of packages in the queue = N
+ // N * {
+ // [utf8] package name
+ // [long] last backup time for this package
+ // }
+ int numPackages = mFullBackupQueue.size();
+ bufOut.writeInt(numPackages);
+
+ for (int i = 0; i < numPackages; i++) {
+ FullBackupEntry entry = mFullBackupQueue.get(i);
+ bufOut.writeUTF(entry.packageName);
+ bufOut.writeLong(entry.lastBackup);
+ }
+ bufOut.flush();
+
+ AtomicFile af = new AtomicFile(mFullBackupScheduleFile);
+ FileOutputStream out = af.startWrite();
+ out.write(bufStream.toByteArray());
+ af.finishWrite(out);
+ } catch (Exception e) {
+ Slog.e(TAG, mLogIdMsg + "Unable to write backup schedule!", e);
+ }
}
- bufOut.flush();
-
- AtomicFile af = new AtomicFile(mFullBackupScheduleFile);
- FileOutputStream out = af.startWrite();
- out.write(bufStream.toByteArray());
- af.finishWrite(out);
- } catch (Exception e) {
- Slog.e(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Unable to write backup schedule!"),
- e);
}
- }
- }
- };
+ };
private void writeFullBackupScheduleAsync() {
mBackupHandler.removeCallbacks(mFullBackupScheduleWriter);
@@ -1044,28 +1057,33 @@ public class UserBackupManagerService {
ArrayList<DataChangedJournal> journals = DataChangedJournal.listJournals(mJournalDir);
journals.removeAll(Collections.singletonList(mJournal));
if (!journals.isEmpty()) {
- Slog.i(TAG, addUserIdToLogMessage(mUserId,
- "Found " + journals.size() + " stale backup journal(s), scheduling."));
+ Slog.i(
+ TAG,
+ mLogIdMsg
+ + "Found "
+ + journals.size()
+ + " stale backup journal(s), scheduling.");
}
Set<String> packageNames = new LinkedHashSet<>();
for (DataChangedJournal journal : journals) {
try {
- journal.forEach(packageName -> {
- if (packageNames.add(packageName)) {
- dataChangedImpl(packageName);
- }
- });
+ journal.forEach(
+ packageName -> {
+ if (packageNames.add(packageName)) {
+ dataChangedImpl(packageName);
+ }
+ });
} catch (IOException e) {
- Slog.e(TAG, addUserIdToLogMessage(mUserId, "Can't read " + journal), e);
+ Slog.e(TAG, mLogIdMsg + "Can't read " + journal, e);
}
}
if (!packageNames.isEmpty()) {
- String msg = "Stale backup journals: Scheduled " + packageNames.size()
- + " package(s) total";
+ String msg =
+ "Stale backup journals: Scheduled " + packageNames.size() + " package(s) total";
if (DEBUG) {
msg += ": " + packageNames;
}
- Slog.i(TAG, addUserIdToLogMessage(mUserId, msg));
+ Slog.i(TAG, mLogIdMsg + msg);
}
}
@@ -1105,12 +1123,11 @@ public class UserBackupManagerService {
if (DEBUG) {
Slog.i(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "recordInitPending("
- + isPending
- + ") on transport "
- + transportName));
+ mLogIdMsg
+ + "recordInitPending("
+ + isPending
+ + ") on transport "
+ + transportName);
}
File stateDir = new File(mBaseStateDir, transportDirName);
@@ -1170,10 +1187,16 @@ public class UserBackupManagerService {
private void onTransportRegistered(String transportName, String transportDirName) {
long timeMs = SystemClock.elapsedRealtime() - mRegisterTransportsRequestedTime;
- Slog.d(TAG, addUserIdToLogMessage(mUserId,
- "Transport " + transportName + " registered " + timeMs
- + "ms after first request (delay = " + INITIALIZATION_DELAY_MILLIS
- + "ms)"));
+ Slog.d(
+ TAG,
+ mLogIdMsg
+ + "Transport "
+ + transportName
+ + " registered "
+ + timeMs
+ + "ms after first request (delay = "
+ + INITIALIZATION_DELAY_MILLIS
+ + "ms)");
File stateDir = new File(mBaseStateDir, transportDirName);
stateDir.mkdirs();
@@ -1185,8 +1208,10 @@ public class UserBackupManagerService {
// TODO: pick a better starting time than now + 1 minute
long delay = 1000 * 60; // one minute, in milliseconds
- mAlarmManager.set(AlarmManager.RTC_WAKEUP,
- System.currentTimeMillis() + delay, mRunInitIntent);
+ mAlarmManager.set(
+ AlarmManager.RTC_WAKEUP,
+ System.currentTimeMillis() + delay,
+ mRunInitIntent);
}
}
}
@@ -1195,137 +1220,131 @@ public class UserBackupManagerService {
* A {@link BroadcastReceiver} tracking changes to packages and sd cards in order to update our
* internal bookkeeping.
*/
- private BroadcastReceiver mPackageTrackingReceiver = new BroadcastReceiver() {
- public void onReceive(Context context, Intent intent) {
- if (DEBUG) {
- Slog.d(TAG, addUserIdToLogMessage(mUserId, "Received broadcast " + intent));
- }
+ private BroadcastReceiver mPackageTrackingReceiver =
+ new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG) {
+ Slog.d(TAG, mLogIdMsg + "Received broadcast " + intent);
+ }
- String action = intent.getAction();
- boolean replacing = false;
- boolean added = false;
- boolean changed = false;
- Bundle extras = intent.getExtras();
- String[] packageList = null;
+ String action = intent.getAction();
+ boolean replacing = false;
+ boolean added = false;
+ boolean changed = false;
+ Bundle extras = intent.getExtras();
+ String[] packageList = null;
+
+ if (Intent.ACTION_PACKAGE_ADDED.equals(action)
+ || Intent.ACTION_PACKAGE_REMOVED.equals(action)
+ || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
+ Uri uri = intent.getData();
+ if (uri == null) {
+ return;
+ }
- if (Intent.ACTION_PACKAGE_ADDED.equals(action)
- || Intent.ACTION_PACKAGE_REMOVED.equals(action)
- || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
- Uri uri = intent.getData();
- if (uri == null) {
- return;
- }
+ String packageName = uri.getSchemeSpecificPart();
+ if (packageName != null) {
+ packageList = new String[] {packageName};
+ }
- String packageName = uri.getSchemeSpecificPart();
- if (packageName != null) {
- packageList = new String[] {packageName};
- }
+ changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
+ if (changed) {
+ // Look at new transport states for package changed events.
+ String[] components =
+ intent.getStringArrayExtra(
+ Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
- changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
- if (changed) {
- // Look at new transport states for package changed events.
- String[] components =
- intent.getStringArrayExtra(
- Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
+ if (DEBUG) {
+ Slog.i(TAG, mLogIdMsg + "Package " + packageName + " changed");
+ for (int i = 0; i < components.length; i++) {
+ Slog.i(TAG, mLogIdMsg + " * " + components[i]);
+ }
+ }
- if (DEBUG) {
- Slog.i(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Package " + packageName + " changed"));
- for (int i = 0; i < components.length; i++) {
- Slog.i(
- TAG,
- addUserIdToLogMessage(
- mUserId, " * " + components[i]));
+ mBackupHandler.post(
+ () ->
+ mTransportManager.onPackageChanged(
+ packageName, components));
+ return;
}
- }
- mBackupHandler.post(
- () ->
- mTransportManager.onPackageChanged(
- packageName, components));
- return;
- }
+ added = Intent.ACTION_PACKAGE_ADDED.equals(action);
+ replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
+ added = true;
+ packageList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
+ added = false;
+ packageList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ }
- added = Intent.ACTION_PACKAGE_ADDED.equals(action);
- replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
- } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
- added = true;
- packageList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
- } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
- added = false;
- packageList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
- }
+ if (packageList == null || packageList.length == 0) {
+ return;
+ }
- if (packageList == null || packageList.length == 0) {
- return;
- }
+ int uid = extras.getInt(Intent.EXTRA_UID);
+ if (added) {
+ synchronized (mBackupParticipants) {
+ if (replacing) {
+ // Remove the entry under the old uid and fall through to re-add. If
+ // an app
+ // just opted into key/value backup, add it as a known participant.
+ removePackageParticipantsLocked(packageList, uid);
+ }
+ addPackageParticipantsLocked(packageList);
+ }
- int uid = extras.getInt(Intent.EXTRA_UID);
- if (added) {
- synchronized (mBackupParticipants) {
- if (replacing) {
- // Remove the entry under the old uid and fall through to re-add. If
- // an app
- // just opted into key/value backup, add it as a known participant.
- removePackageParticipantsLocked(packageList, uid);
- }
- addPackageParticipantsLocked(packageList);
- }
+ long now = System.currentTimeMillis();
+ for (String packageName : packageList) {
+ try {
+ PackageInfo app =
+ mPackageManager.getPackageInfoAsUser(
+ packageName, /* flags */ 0, mUserId);
+ if (mScheduledBackupEligibility.appGetsFullBackup(app)
+ && mScheduledBackupEligibility.appIsEligibleForBackup(
+ app.applicationInfo)) {
+ enqueueFullBackup(packageName, now);
+ scheduleNextFullBackupJob(0);
+ } else {
+ // The app might have just transitioned out of full-data into
+ // doing
+ // key/value backups, or might have just disabled backups
+ // entirely. Make
+ // sure it is no longer in the full-data queue.
+ synchronized (mQueueLock) {
+ dequeueFullBackupLocked(packageName);
+ }
+ writeFullBackupScheduleAsync();
+ }
- long now = System.currentTimeMillis();
- for (String packageName : packageList) {
- try {
- PackageInfo app =
- mPackageManager.getPackageInfoAsUser(
- packageName, /* flags */ 0, mUserId);
- if (mScheduledBackupEligibility.appGetsFullBackup(app)
- && mScheduledBackupEligibility.appIsEligibleForBackup(
- app.applicationInfo)) {
- enqueueFullBackup(packageName, now);
- scheduleNextFullBackupJob(0);
- } else {
- // The app might have just transitioned out of full-data into
- // doing
- // key/value backups, or might have just disabled backups
- // entirely. Make
- // sure it is no longer in the full-data queue.
- synchronized (mQueueLock) {
- dequeueFullBackupLocked(packageName);
+ mBackupHandler.post(
+ () -> mTransportManager.onPackageAdded(packageName));
+ } catch (NameNotFoundException e) {
+ Slog.w(TAG, mLogIdMsg + "Can't resolve new app " + packageName);
}
- writeFullBackupScheduleAsync();
}
- mBackupHandler.post(
- () -> mTransportManager.onPackageAdded(packageName));
- } catch (NameNotFoundException e) {
- Slog.w(TAG, addUserIdToLogMessage(mUserId,
- "Can't resolve new app " + packageName));
- }
- }
+ // Whenever a package is added or updated we need to update the package
+ // metadata
+ // bookkeeping.
+ dataChangedImpl(PACKAGE_MANAGER_SENTINEL);
+ } else {
+ if (!replacing) {
+ // Outright removal. In the full-data case, the app will be dropped from
+ // the
+ // queue when its (now obsolete) name comes up again for backup.
+ synchronized (mBackupParticipants) {
+ removePackageParticipantsLocked(packageList, uid);
+ }
+ }
- // Whenever a package is added or updated we need to update the package
- // metadata
- // bookkeeping.
- dataChangedImpl(PACKAGE_MANAGER_SENTINEL);
- } else {
- if (!replacing) {
- // Outright removal. In the full-data case, the app will be dropped from
- // the
- // queue when its (now obsolete) name comes up again for backup.
- synchronized (mBackupParticipants) {
- removePackageParticipantsLocked(packageList, uid);
+ for (String packageName : packageList) {
+ mBackupHandler.post(
+ () -> mTransportManager.onPackageRemoved(packageName));
+ }
}
}
-
- for (String packageName : packageList) {
- mBackupHandler.post(
- () -> mTransportManager.onPackageRemoved(packageName));
- }
- }
- }
- };
+ };
// Add the backup agents in the given packages to our set of known backup participants.
// If 'packageNames' is null, adds all backup agents in the whole system.
@@ -1334,29 +1353,23 @@ public class UserBackupManagerService {
List<PackageInfo> targetApps = allAgentPackages();
if (packageNames != null) {
if (DEBUG) {
- Slog.v(
- TAG,
- addUserIdToLogMessage(
- mUserId, "addPackageParticipantsLocked: #" + packageNames.length));
+ Slog.v(TAG, mLogIdMsg + "addPackageParticipantsLocked: #" + packageNames.length);
}
for (String packageName : packageNames) {
addPackageParticipantsLockedInner(packageName, targetApps);
}
} else {
if (DEBUG) {
- Slog.v(TAG, addUserIdToLogMessage(mUserId, "addPackageParticipantsLocked: all"));
+ Slog.v(TAG, mLogIdMsg + "addPackageParticipantsLocked: all");
}
addPackageParticipantsLockedInner(null, targetApps);
}
}
- private void addPackageParticipantsLockedInner(String packageName,
- List<PackageInfo> targetPkgs) {
+ private void addPackageParticipantsLockedInner(
+ String packageName, List<PackageInfo> targetPkgs) {
if (DEBUG) {
- Slog.v(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Examining " + packageName + " for backup agent"));
+ Slog.v(TAG, mLogIdMsg + "Examining " + packageName + " for backup agent");
}
for (PackageInfo pkg : targetPkgs) {
@@ -1368,17 +1381,14 @@ public class UserBackupManagerService {
mBackupParticipants.put(uid, set);
}
set.add(pkg.packageName);
- if (DEBUG) Slog.v(TAG, addUserIdToLogMessage(mUserId, "Agent found; added"));
+ if (DEBUG) Slog.v(TAG, mLogIdMsg + "Agent found; added");
// Schedule a backup for it on general principles
if (DEBUG) {
- Slog.i(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Scheduling backup for new app " + pkg.packageName));
+ Slog.i(TAG, mLogIdMsg + "Scheduling backup for new app " + pkg.packageName);
}
- Message msg = mBackupHandler
- .obtainMessage(MSG_SCHEDULE_BACKUP_PACKAGE, pkg.packageName);
+ Message msg =
+ mBackupHandler.obtainMessage(MSG_SCHEDULE_BACKUP_PACKAGE, pkg.packageName);
mBackupHandler.sendMessage(msg);
}
}
@@ -1387,19 +1397,18 @@ public class UserBackupManagerService {
// Remove the given packages' entries from our known active set.
private void removePackageParticipantsLocked(String[] packageNames, int oldUid) {
if (packageNames == null) {
- Slog.w(TAG, addUserIdToLogMessage(mUserId, "removePackageParticipants with null list"));
+ Slog.w(TAG, mLogIdMsg + "removePackageParticipants with null list");
return;
}
if (DEBUG) {
Slog.v(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "removePackageParticipantsLocked: uid="
- + oldUid
- + " #"
- + packageNames.length));
+ mLogIdMsg
+ + "removePackageParticipantsLocked: uid="
+ + oldUid
+ + " #"
+ + packageNames.length);
}
for (String pkg : packageNames) {
// Known previous UID, so we know which package set to check
@@ -1408,10 +1417,7 @@ public class UserBackupManagerService {
removePackageFromSetLocked(set, pkg);
if (set.isEmpty()) {
if (DEBUG) {
- Slog.v(
- TAG,
- addUserIdToLogMessage(
- mUserId, " last one of this uid; purging set"));
+ Slog.v(TAG, mLogIdMsg + " last one of this uid; purging set");
}
mBackupParticipants.remove(oldUid);
}
@@ -1419,8 +1425,7 @@ public class UserBackupManagerService {
}
}
- private void removePackageFromSetLocked(final HashSet<String> set,
- final String packageName) {
+ private void removePackageFromSetLocked(final HashSet<String> set, final String packageName) {
if (set.contains(packageName)) {
// Found it. Remove this one package from the bookkeeping, and
// if it's the last participating app under this uid we drop the
@@ -1429,9 +1434,7 @@ public class UserBackupManagerService {
// bookkeeping so that its current-dataset data will be retrieved
// if the app is subsequently reinstalled
if (DEBUG) {
- Slog.v(
- TAG,
- addUserIdToLogMessage(mUserId, " removing participant " + packageName));
+ Slog.v(TAG, mLogIdMsg + " removing participant " + packageName);
}
set.remove(packageName);
mPendingBackups.remove(packageName);
@@ -1456,8 +1459,11 @@ public class UserBackupManagerService {
// we will need the shared library path, so look that up and store it here.
// This is used implicitly when we pass the PackageInfo object off to
// the Activity Manager to launch the app for backup/restore purposes.
- app = mPackageManager.getApplicationInfoAsUser(pkg.packageName,
- PackageManager.GET_SHARED_LIBRARY_FILES, mUserId);
+ app =
+ mPackageManager.getApplicationInfoAsUser(
+ pkg.packageName,
+ PackageManager.GET_SHARED_LIBRARY_FILES,
+ mUserId);
pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles;
pkg.applicationInfo.sharedLibraryInfos = app.sharedLibraryInfos;
}
@@ -1479,8 +1485,8 @@ public class UserBackupManagerService {
final Intent notification = new Intent();
notification.setAction(BACKUP_FINISHED_ACTION);
notification.setPackage(receiver);
- notification.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES
- | Intent.FLAG_RECEIVER_FOREGROUND);
+ notification.addFlags(
+ Intent.FLAG_INCLUDE_STOPPED_PACKAGES | Intent.FLAG_RECEIVER_FOREGROUND);
notification.putExtra(BACKUP_FINISHED_PACKAGE_EXTRA, packageName);
mContext.sendBroadcastAsUser(notification, UserHandle.of(mUserId));
}
@@ -1506,17 +1512,14 @@ public class UserBackupManagerService {
af.writeInt(-1);
} else {
af.writeInt(mAncestralPackages.size());
- Slog.d(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Ancestral packages: " + mAncestralPackages.size()));
+ Slog.d(TAG, mLogIdMsg + "Ancestral packages: " + mAncestralPackages.size());
for (String pkgName : mAncestralPackages) {
af.writeUTF(pkgName);
- if (DEBUG) Slog.v(TAG, addUserIdToLogMessage(mUserId, " " + pkgName));
+ if (DEBUG) Slog.v(TAG, mLogIdMsg + " " + pkgName);
}
}
} catch (IOException e) {
- Slog.w(TAG, addUserIdToLogMessage(mUserId, "Unable to write token file:"), e);
+ Slog.w(TAG, mLogIdMsg + "Unable to write token file:", e);
}
}
@@ -1539,45 +1542,39 @@ public class UserBackupManagerService {
/**
* Clear an application's data, blocking until the operation completes or times out.
*
- * @param checkFlagAllowClearUserDataOnFailedRestore if {@code true} uses
- * {@link ApplicationInfo#PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE} to decide if
- * clearing data is allowed after a failed restore.
- *
+ * @param checkFlagAllowClearUserDataOnFailedRestore if {@code true} uses {@link
+ * ApplicationInfo#PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE} to decide if
+ * clearing data is allowed after a failed restore.
* @param keepSystemState if {@code true}, we don't clear system state such as already restored
- * notification settings, permission grants, etc.
+ * notification settings, permission grants, etc.
*/
- private void clearApplicationDataSynchronous(String packageName,
- boolean checkFlagAllowClearUserDataOnFailedRestore, boolean keepSystemState) {
+ private void clearApplicationDataSynchronous(
+ String packageName,
+ boolean checkFlagAllowClearUserDataOnFailedRestore,
+ boolean keepSystemState) {
try {
- ApplicationInfo applicationInfo = mPackageManager.getPackageInfoAsUser(
- packageName, 0, mUserId).applicationInfo;
+ ApplicationInfo applicationInfo =
+ mPackageManager.getPackageInfoAsUser(packageName, 0, mUserId).applicationInfo;
boolean shouldClearData;
if (checkFlagAllowClearUserDataOnFailedRestore
&& applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q) {
- shouldClearData = (applicationInfo.privateFlags
- & ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE) != 0;
+ int clearOnFailedRestoreFlag =
+ ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE;
+ shouldClearData = (applicationInfo.privateFlags & clearOnFailedRestoreFlag) != 0;
} else {
shouldClearData =
- (applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) != 0;
+ (applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) != 0;
}
if (!shouldClearData) {
if (DEBUG) {
- Slog.i(
- TAG,
- addUserIdToLogMessage(
- mUserId,
- "Clearing app data is not allowed so not wiping "
- + packageName));
+ Slog.i(TAG, mLogIdMsg + "Clearing app data is not allowed " + packageName);
}
return;
}
} catch (NameNotFoundException e) {
- Slog.w(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Tried to clear data for " + packageName + " but not found"));
+ Slog.w(TAG, mLogIdMsg + "Tried to clear data for " + packageName + " but not found");
return;
}
@@ -1585,8 +1582,8 @@ public class UserBackupManagerService {
synchronized (mClearDataLock) {
mClearingData = true;
- mActivityManagerInternal.clearApplicationUserData(packageName, keepSystemState,
- /*isRestore=*/ true, observer, mUserId);
+ mActivityManagerInternal.clearApplicationUserData(
+ packageName, keepSystemState, /* isRestore= */ true, observer, mUserId);
// Only wait 30 seconds for the clear data to happen.
long timeoutMark = System.currentTimeMillis() + CLEAR_DATA_TIMEOUT_INTERVAL;
@@ -1598,20 +1595,16 @@ public class UserBackupManagerService {
mClearingData = false;
Slog.w(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "Interrupted while waiting for "
- + packageName
- + " data to be cleared"),
+ mLogIdMsg
+ + "Interrupted while waiting for "
+ + packageName
+ + " data to be cleared",
e);
}
}
if (mClearingData) {
- Slog.w(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Clearing app data for " + packageName + " timed out"));
+ Slog.w(TAG, mLogIdMsg + "Clearing app data for " + packageName + " timed out");
}
}
}
@@ -1632,23 +1625,20 @@ public class UserBackupManagerService {
* the active set if possible, else the ancestral one. Returns zero if none available.
*/
public long getAvailableRestoreToken(String packageName) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "getAvailableRestoreToken");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BACKUP, "getAvailableRestoreToken");
long token = mAncestralToken;
synchronized (mQueueLock) {
if (mCurrentToken != 0 && mProcessedPackagesJournal.hasBeenProcessed(packageName)) {
if (DEBUG) {
- Slog.i(
- TAG,
- addUserIdToLogMessage(
- mUserId, "App in ever-stored, so using current token"));
+ Slog.i(TAG, mLogIdMsg + "App in ever-stored, so using current token");
}
token = mCurrentToken;
}
}
if (DEBUG) {
- Slog.i(TAG, addUserIdToLogMessage(mUserId, "getAvailableRestoreToken() == " + token));
+ Slog.i(TAG, mLogIdMsg + "getAvailableRestoreToken() == " + token);
}
return token;
}
@@ -1666,35 +1656,40 @@ public class UserBackupManagerService {
* Requests a backup for the inputted {@code packages} with a specified {@link
* IBackupManagerMonitor} and {@link OperationType}.
*/
- public int requestBackup(String[] packages, IBackupObserver observer,
- IBackupManagerMonitor monitor, int flags) {
- BackupManagerMonitorEventSender mBackupManagerMonitorEventSender =
+ public int requestBackup(
+ String[] packages, IBackupObserver observer, IBackupManagerMonitor monitor, int flags) {
+ BackupManagerMonitorEventSender mBackupManagerMonitorEventSender =
getBMMEventSender(monitor);
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "requestBackup");
if (packages == null || packages.length < 1) {
- Slog.e(TAG, addUserIdToLogMessage(mUserId, "No packages named for backup request"));
+ Slog.e(TAG, mLogIdMsg + "No packages named for backup request");
BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
mBackupManagerMonitorEventSender.monitorEvent(
- BackupManagerMonitor.LOG_EVENT_ID_NO_PACKAGES,
- null, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null);
+ BackupManagerMonitor.LOG_EVENT_ID_NO_PACKAGES, null,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null);
throw new IllegalArgumentException("No packages are provided for backup");
}
if (!mEnabled || !mSetupComplete) {
Slog.i(
TAG,
- addUserIdToLogMessage(mUserId, "Backup requested but enabled="
+ mLogIdMsg
+ + "Backup requested but enabled="
+ mEnabled
+ " setupComplete="
- + mSetupComplete));
- BackupObserverUtils.sendBackupFinished(observer,
- BackupManager.ERROR_BACKUP_NOT_ALLOWED);
- final int logTag = mSetupComplete
- ? BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED
- : BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED;
- mBackupManagerMonitorEventSender.monitorEvent(logTag, null,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null);
+ + mSetupComplete);
+ BackupObserverUtils.sendBackupFinished(
+ observer, BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+ final int logTag =
+ mSetupComplete
+ ? BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED
+ : BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED;
+ mBackupManagerMonitorEventSender.monitorEvent(
+ logTag,
+ null,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ null);
return BackupManager.ERROR_BACKUP_NOT_ALLOWED;
}
@@ -1708,31 +1703,45 @@ public class UserBackupManagerService {
transportConnection =
mTransportManager.getCurrentTransportClientOrThrow("BMS.requestBackup()");
backupDestination = getBackupDestinationFromTransport(transportConnection);
- } catch (TransportNotRegisteredException | TransportNotAvailableException
+ } catch (TransportNotRegisteredException
+ | TransportNotAvailableException
| RemoteException e) {
BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
mBackupManagerMonitorEventSender.monitorEvent(
- BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_IS_NULL,
- null, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null);
+ BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_IS_NULL, null,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null);
return BackupManager.ERROR_TRANSPORT_ABORTED;
}
OnTaskFinishedListener listener =
caller -> mTransportManager.disposeOfTransportClient(transportConnection, caller);
- BackupEligibilityRules backupEligibilityRules = getEligibilityRulesForOperation(
- backupDestination);
+ BackupEligibilityRules backupEligibilityRules =
+ getEligibilityRulesForOperation(backupDestination);
Message msg = mBackupHandler.obtainMessage(MSG_REQUEST_BACKUP);
- msg.obj = getRequestBackupParams(packages, observer, monitor, flags, backupEligibilityRules,
- transportConnection, transportDirName, listener);
+ msg.obj =
+ getRequestBackupParams(
+ packages,
+ observer,
+ monitor,
+ flags,
+ backupEligibilityRules,
+ transportConnection,
+ transportDirName,
+ listener);
mBackupHandler.sendMessage(msg);
return BackupManager.SUCCESS;
}
@VisibleForTesting
- BackupParams getRequestBackupParams(String[] packages, IBackupObserver observer,
- IBackupManagerMonitor monitor, int flags, BackupEligibilityRules backupEligibilityRules,
- TransportConnection transportConnection, String transportDirName,
+ BackupParams getRequestBackupParams(
+ String[] packages,
+ IBackupObserver observer,
+ IBackupManagerMonitor monitor,
+ int flags,
+ BackupEligibilityRules backupEligibilityRules,
+ TransportConnection transportConnection,
+ String transportDirName,
OnTaskFinishedListener listener) {
ArrayList<String> fullBackupList = new ArrayList<>();
ArrayList<String> kvBackupList = new ArrayList<>();
@@ -1742,11 +1751,12 @@ public class UserBackupManagerService {
continue;
}
try {
- PackageInfo packageInfo = mPackageManager.getPackageInfoAsUser(packageName,
- PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
+ PackageInfo packageInfo =
+ mPackageManager.getPackageInfoAsUser(
+ packageName, PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
if (!backupEligibilityRules.appIsEligibleForBackup(packageInfo.applicationInfo)) {
- BackupObserverUtils.sendBackupOnPackageResult(observer, packageName,
- BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+ BackupObserverUtils.sendBackupOnPackageResult(
+ observer, packageName, BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
}
if (backupEligibilityRules.appGetsFullBackup(packageInfo)) {
@@ -1755,31 +1765,41 @@ public class UserBackupManagerService {
kvBackupList.add(packageInfo.packageName);
}
} catch (NameNotFoundException e) {
- BackupObserverUtils.sendBackupOnPackageResult(observer, packageName,
- BackupManager.ERROR_PACKAGE_NOT_FOUND);
+ BackupObserverUtils.sendBackupOnPackageResult(
+ observer, packageName, BackupManager.ERROR_PACKAGE_NOT_FOUND);
}
}
- EventLog.writeEvent(EventLogTags.BACKUP_REQUESTED, packages.length, kvBackupList.size(),
+ EventLog.writeEvent(
+ EventLogTags.BACKUP_REQUESTED,
+ packages.length,
+ kvBackupList.size(),
fullBackupList.size());
if (DEBUG) {
Slog.i(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "Backup requested for "
- + packages.length
- + " packages, of them: "
- + fullBackupList.size()
- + " full backups, "
- + kvBackupList.size()
- + " k/v backups"));
+ mLogIdMsg
+ + "Backup requested for "
+ + packages.length
+ + " packages, of them: "
+ + fullBackupList.size()
+ + " full backups, "
+ + kvBackupList.size()
+ + " k/v backups");
}
boolean nonIncrementalBackup = (flags & BackupManager.FLAG_NON_INCREMENTAL_BACKUP) != 0;
- return new BackupParams(transportConnection, transportDirName, kvBackupList, fullBackupList,
- observer, monitor, listener, /* userInitiated */ true, nonIncrementalBackup,
+ return new BackupParams(
+ transportConnection,
+ transportDirName,
+ kvBackupList,
+ fullBackupList,
+ observer,
+ monitor,
+ listener, /* userInitiated */
+ true,
+ nonIncrementalBackup,
backupEligibilityRules);
}
@@ -1787,7 +1807,7 @@ public class UserBackupManagerService {
public void cancelBackups() {
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "cancelBackups");
if (DEBUG) {
- Slog.i(TAG, addUserIdToLogMessage(mUserId, "cancelBackups() called."));
+ Slog.i(TAG, mLogIdMsg + "cancelBackups() called.");
}
final long oldToken = Binder.clearCallingIdentity();
try {
@@ -1795,14 +1815,24 @@ public class UserBackupManagerService {
mOperationStorage.operationTokensForOpType(OpType.BACKUP);
for (Integer token : operationsToCancel) {
- mOperationStorage.cancelOperation(token, /* cancelAll */ true,
- operationType -> { /* no callback needed here */ });
+ mOperationStorage.cancelOperation(
+ token, /* cancelAll */
+ true,
+ operationType -> {
+ /* no callback needed here */
+ });
}
// We don't want the backup jobs to kick in any time soon.
// Reschedules them to run in the distant future.
- KeyValueBackupJob.schedule(mUserId, mContext, BUSY_BACKOFF_MIN_MILLIS,
+ KeyValueBackupJob.schedule(
+ mUserId,
+ mContext,
+ BUSY_BACKOFF_MIN_MILLIS,
/* userBackupManagerService */ this);
- FullBackupJob.schedule(mUserId, mContext, 2 * BUSY_BACKOFF_MIN_MILLIS,
+ FullBackupJob.schedule(
+ mUserId,
+ mContext,
+ 2 * BUSY_BACKOFF_MIN_MILLIS,
/* userBackupManagerService */ this);
} finally {
Binder.restoreCallingIdentity(oldToken);
@@ -1810,35 +1840,34 @@ public class UserBackupManagerService {
}
/** Schedule a timeout message for the operation identified by {@code token}. */
- public void prepareOperationTimeout(int token, long interval, BackupRestoreTask callback,
- int operationType) {
+ public void prepareOperationTimeout(
+ int token, long interval, BackupRestoreTask callback, int operationType) {
if (operationType != OpType.BACKUP_WAIT && operationType != OpType.RESTORE_WAIT) {
Slog.wtf(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "prepareOperationTimeout() doesn't support operation "
- + Integer.toHexString(token)
- + " of type "
- + operationType));
+ mLogIdMsg
+ + "prepareOperationTimeout() doesn't support operation "
+ + Integer.toHexString(token)
+ + " of type "
+ + operationType);
return;
}
if (DEBUG) {
Slog.v(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "starting timeout: token="
- + Integer.toHexString(token)
- + " interval="
- + interval
- + " callback="
- + callback));
+ mLogIdMsg
+ + "starting timeout: token="
+ + Integer.toHexString(token)
+ + " interval="
+ + interval
+ + " callback="
+ + callback);
}
mOperationStorage.registerOperation(token, OpState.PENDING, callback, operationType);
- Message msg = mBackupHandler.obtainMessage(getMessageIdForOperationType(operationType),
- token, 0, callback);
+ Message msg =
+ mBackupHandler.obtainMessage(
+ getMessageIdForOperationType(operationType), token, 0, callback);
mBackupHandler.sendMessageDelayed(msg, interval);
}
@@ -1851,19 +1880,20 @@ public class UserBackupManagerService {
default:
Slog.wtf(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "getMessageIdForOperationType called on invalid operation type: "
- + operationType));
+ mLogIdMsg
+ + "getMessageIdForOperationType called on invalid operation type: "
+ + operationType);
return -1;
}
}
/** Block until we received an operation complete message (from the agent or cancellation). */
public boolean waitUntilOperationComplete(int token) {
- return mOperationStorage.waitUntilOperationComplete(token, operationType -> {
- mBackupHandler.removeMessages(getMessageIdForOperationType(operationType));
- });
+ return mOperationStorage.waitUntilOperationComplete(
+ token,
+ operationType -> {
+ mBackupHandler.removeMessages(getMessageIdForOperationType(operationType));
+ });
}
/** Cancel the operation associated with {@code token}. */
@@ -1871,11 +1901,15 @@ public class UserBackupManagerService {
// Remove all pending timeout messages of types OpType.BACKUP_WAIT and
// OpType.RESTORE_WAIT. On the other hand, OP_TYPE_BACKUP cannot time out and
// doesn't require cancellation.
- mOperationStorage.cancelOperation(token, cancelAll, operationType -> {
- if (operationType == OpType.BACKUP_WAIT || operationType == OpType.RESTORE_WAIT) {
- mBackupHandler.removeMessages(getMessageIdForOperationType(operationType));
- }
- });
+ mOperationStorage.cancelOperation(
+ token,
+ cancelAll,
+ operationType -> {
+ if (operationType == OpType.BACKUP_WAIT
+ || operationType == OpType.RESTORE_WAIT) {
+ mBackupHandler.removeMessages(getMessageIdForOperationType(operationType));
+ }
+ });
}
/** Returns {@code true} if a backup is currently running, else returns {@code false}. */
@@ -1885,9 +1919,7 @@ public class UserBackupManagerService {
// ----- Full-data backup scheduling -----
- /**
- * Schedule a job to tell us when it's a good time to run a full backup
- */
+ /** Schedule a job to tell us when it's a good time to run a full backup */
public void scheduleNextFullBackupJob(long transportMinLatency) {
synchronized (mQueueLock) {
if (mFullBackupQueue.size() > 0) {
@@ -1899,18 +1931,15 @@ public class UserBackupManagerService {
final long interval = mConstants.getFullBackupIntervalMilliseconds();
final long appLatency = (timeSinceLast < interval) ? (interval - timeSinceLast) : 0;
final long latency = Math.max(transportMinLatency, appLatency);
- FullBackupJob.schedule(mUserId, mContext, latency,
- /* userBackupManagerService */ this);
+ FullBackupJob.schedule(
+ mUserId, mContext, latency, /* userBackupManagerService */ this);
} else {
- Slog.i(TAG,
- addUserIdToLogMessage(mUserId, "Full backup queue empty; not scheduling"));
+ Slog.i(TAG, mLogIdMsg + "Full backup queue empty; not scheduling");
}
}
}
- /**
- * Remove a package from the full-data queue.
- */
+ /** Remove a package from the full-data queue. */
@GuardedBy("mQueueLock")
private void dequeueFullBackupLocked(String packageName) {
final int numPackages = mFullBackupQueue.size();
@@ -1922,9 +1951,7 @@ public class UserBackupManagerService {
}
}
- /**
- * Enqueue full backup for the given app, with a note about when it last ran.
- */
+ /** Enqueue full backup for the given app, with a note about when it last ran. */
public void enqueueFullBackup(String packageName, long lastBackedUp) {
FullBackupEntry newEntry = new FullBackupEntry(packageName, lastBackedUp);
synchronized (mQueueLock) {
@@ -1957,10 +1984,7 @@ public class UserBackupManagerService {
private boolean fullBackupAllowable(String transportName) {
if (!mTransportManager.isTransportRegistered(transportName)) {
- Slog.w(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Transport not registered; full data backup not performed"));
+ Slog.w(TAG, mLogIdMsg + "Transport not registered; full data backup not performed");
return false;
}
@@ -1971,15 +1995,11 @@ public class UserBackupManagerService {
File stateDir = new File(mBaseStateDir, transportDirName);
File pmState = new File(stateDir, PACKAGE_MANAGER_SENTINEL);
if (pmState.length() <= 0) {
- Slog.i(TAG, addUserIdToLogMessage(mUserId,
- "Full backup requested but dataset not yet initialized"));
+ Slog.i(TAG, mLogIdMsg + "Full backup requested but dataset not yet initialized");
return false;
}
} catch (Exception e) {
- Slog.w(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Unable to get transport name: " + e.getMessage()));
+ Slog.w(TAG, mLogIdMsg + "Unable to get transport name: " + e.getMessage());
return false;
}
@@ -1987,14 +2007,14 @@ public class UserBackupManagerService {
}
/**
- * Conditions are right for a full backup operation, so run one. The model we use is
- * to perform one app backup per scheduled job execution, and to reschedule the job
- * with zero latency as long as conditions remain right and we still have work to do.
+ * Conditions are right for a full backup operation, so run one. The model we use is to perform
+ * one app backup per scheduled job execution, and to reschedule the job with zero latency as
+ * long as conditions remain right and we still have work to do.
*
* <p>This is the "start a full backup operation" entry point called by the scheduled job.
*
- * @return Whether ongoing work will continue. The return value here will be passed
- * along as the return value to the scheduled job's onStartJob() callback.
+ * @return Whether ongoing work will continue. The return value here will be passed along as the
+ * return value to the scheduled job's onStartJob() callback.
*/
public boolean beginFullBackup(FullBackupJob scheduledJob) {
final long now = System.currentTimeMillis();
@@ -2012,33 +2032,34 @@ public class UserBackupManagerService {
// the job driving automatic backups; that job will be scheduled again when
// the user enables backup.
if (DEBUG) {
- Slog.i(TAG, addUserIdToLogMessage(mUserId, "beginFullBackup but enabled=" + mEnabled
- + " setupComplete=" + mSetupComplete + "; ignoring"));
+ Slog.i(
+ TAG,
+ mLogIdMsg
+ + "beginFullBackup but enabled="
+ + mEnabled
+ + " setupComplete="
+ + mSetupComplete
+ + "; ignoring");
}
return false;
}
// Don't run the backup if we're in battery saver mode, but reschedule
// to try again in the not-so-distant future.
- final PowerSaveState result =
- mPowerManager.getPowerSaveState(ServiceType.FULL_BACKUP);
+ final PowerSaveState result = mPowerManager.getPowerSaveState(ServiceType.FULL_BACKUP);
if (result.batterySaverEnabled) {
- Slog.i(TAG, addUserIdToLogMessage(mUserId,
- "Deferring scheduled full backups in battery saver mode"));
- FullBackupJob.schedule(mUserId, mContext, keyValueBackupInterval,
- /* userBackupManagerService */ this);
+ Slog.i(TAG, mLogIdMsg + "Deferring scheduled full backups in battery saver mode");
+ FullBackupJob.schedule(
+ mUserId, mContext, keyValueBackupInterval, /* userBackupManagerService */ this);
return false;
}
- Slog.i(TAG, addUserIdToLogMessage(mUserId, "Beginning scheduled full backup operation"));
+ Slog.i(TAG, mLogIdMsg + "Beginning scheduled full backup operation");
// Great; we're able to run full backup jobs now. See if we have any work to do.
synchronized (mQueueLock) {
if (mRunningFullBackupTask != null) {
- Slog.e(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Backup triggered but one already/still running!"));
+ Slog.e(TAG, mLogIdMsg + "Backup triggered but one already/still running!");
return false;
}
@@ -2053,8 +2074,7 @@ public class UserBackupManagerService {
// have emptied the queue.
if (mFullBackupQueue.size() == 0) {
// no work to do so just bow out
- Slog.i(TAG,
- addUserIdToLogMessage(mUserId, "Backup queue empty; doing nothing"));
+ Slog.i(TAG, mLogIdMsg + "Backup queue empty; doing nothing");
runBackup = false;
break;
}
@@ -2064,10 +2084,7 @@ public class UserBackupManagerService {
String transportName = mTransportManager.getCurrentTransportName();
if (!fullBackupAllowable(transportName)) {
if (DEBUG) {
- Slog.i(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Preconditions not met; not running full backup"));
+ Slog.i(TAG, mLogIdMsg + "Preconditions not met; not running full backup");
}
runBackup = false;
// Typically this means we haven't run a key/value backup yet. Back off
@@ -2085,18 +2102,16 @@ public class UserBackupManagerService {
if (DEBUG) {
Slog.i(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "Device ready but too early to back up next app"));
+ mLogIdMsg + "Device ready but too early to back up next app");
}
// Wait until the next app in the queue falls due for a full data backup
latency = fullBackupInterval - timeSinceRun;
- break; // we know we aren't doing work yet, so bail.
+ break; // we know we aren't doing work yet, so bail.
}
try {
- PackageInfo appInfo = mPackageManager.getPackageInfoAsUser(
- entry.packageName, 0, mUserId);
+ PackageInfo appInfo =
+ mPackageManager.getPackageInfoAsUser(entry.packageName, 0, mUserId);
if (!mScheduledBackupEligibility.appGetsFullBackup(appInfo)) {
// The head app isn't supposed to get full-data backups [any more];
// so we cull it and force a loop around to consider the new head
@@ -2104,12 +2119,11 @@ public class UserBackupManagerService {
if (DEBUG) {
Slog.i(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "Culling package "
- + entry.packageName
- + " in full-backup queue but not"
- + " eligible"));
+ mLogIdMsg
+ + "Culling package "
+ + entry.packageName
+ + " in full-backup queue but not"
+ + " eligible");
}
mFullBackupQueue.remove(0);
headBusy = true; // force the while() condition
@@ -2117,19 +2131,24 @@ public class UserBackupManagerService {
}
final int privFlags = appInfo.applicationInfo.privateFlags;
- headBusy = (privFlags & PRIVATE_FLAG_BACKUP_IN_FOREGROUND) == 0
- && mActivityManagerInternal.isAppForeground(
- appInfo.applicationInfo.uid);
+ headBusy =
+ (privFlags & PRIVATE_FLAG_BACKUP_IN_FOREGROUND) == 0
+ && mActivityManagerInternal.isAppForeground(
+ appInfo.applicationInfo.uid);
if (headBusy) {
- final long nextEligible = System.currentTimeMillis()
- + BUSY_BACKOFF_MIN_MILLIS
- + mTokenGenerator.nextInt(BUSY_BACKOFF_FUZZ);
+ final long nextEligible =
+ System.currentTimeMillis()
+ + BUSY_BACKOFF_MIN_MILLIS
+ + mTokenGenerator.nextInt(BUSY_BACKOFF_FUZZ);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- Slog.i(TAG, addUserIdToLogMessage(mUserId,
- "Full backup time but " + entry.packageName
- + " is busy; deferring to " + sdf.format(
- new Date(nextEligible))));
+ Slog.i(
+ TAG,
+ mLogIdMsg
+ + "Full backup time but "
+ + entry.packageName
+ + " is busy; deferring to "
+ + sdf.format(new Date(nextEligible)));
// This relocates the app's entry from the head of the queue to
// its order-appropriate position further down, so upon looping
// a new candidate will be considered at the head.
@@ -2147,21 +2166,22 @@ public class UserBackupManagerService {
if (runBackup) {
CountDownLatch latch = new CountDownLatch(1);
- String[] pkg = new String[]{entry.packageName};
+ String[] pkg = new String[] {entry.packageName};
try {
- mRunningFullBackupTask = PerformFullTransportBackupTask.newWithCurrentTransport(
- this,
- mOperationStorage,
- /* observer */ null,
- pkg,
- /* updateSchedule */ true,
- scheduledJob,
- latch,
- /* backupObserver */ null,
- /* monitor */ null,
- /* userInitiated */ false,
- "BMS.beginFullBackup()",
- getEligibilityRulesForOperation(BackupDestination.CLOUD));
+ mRunningFullBackupTask =
+ PerformFullTransportBackupTask.newWithCurrentTransport(
+ this,
+ mOperationStorage,
+ /* observer */ null,
+ pkg,
+ /* updateSchedule */ true,
+ scheduledJob,
+ latch,
+ /* backupObserver */ null,
+ /* monitor */ null,
+ /* userInitiated */ false,
+ "BMS.beginFullBackup()",
+ getEligibilityRulesForOperation(BackupDestination.CLOUD));
} catch (IllegalStateException e) {
Slog.w(TAG, "Failed to start backup", e);
runBackup = false;
@@ -2169,12 +2189,15 @@ public class UserBackupManagerService {
}
if (!runBackup) {
- Slog.i(TAG, addUserIdToLogMessage(mUserId,
- "Nothing pending full backup or failed to start the "
- + "operation; rescheduling +" + latency));
- final long deferTime = latency; // pin for the closure
- FullBackupJob.schedule(mUserId, mContext, deferTime,
- /* userBackupManagerService */ this);
+ Slog.i(
+ TAG,
+ mLogIdMsg
+ + "Nothing pending full backup or failed to start the "
+ + "operation; rescheduling +"
+ + latency);
+ final long deferTime = latency; // pin for the closure
+ FullBackupJob.schedule(
+ mUserId, mContext, deferTime, /* userBackupManagerService */ this);
return false;
}
@@ -2195,21 +2218,22 @@ public class UserBackupManagerService {
public void endFullBackup() {
// offload the mRunningFullBackupTask.handleCancel() call to another thread,
// as we might have to wait for mCancelLock
- Runnable endFullBackupRunnable = new Runnable() {
- @Override
- public void run() {
- PerformFullTransportBackupTask pftbt = null;
- synchronized (mQueueLock) {
- if (mRunningFullBackupTask != null) {
- pftbt = mRunningFullBackupTask;
+ Runnable endFullBackupRunnable =
+ new Runnable() {
+ @Override
+ public void run() {
+ PerformFullTransportBackupTask pftbt = null;
+ synchronized (mQueueLock) {
+ if (mRunningFullBackupTask != null) {
+ pftbt = mRunningFullBackupTask;
+ }
+ }
+ if (pftbt != null) {
+ Slog.i(TAG, mLogIdMsg + "Telling running backup to stop");
+ pftbt.handleCancel(true);
+ }
}
- }
- if (pftbt != null) {
- Slog.i(TAG, addUserIdToLogMessage(mUserId, "Telling running backup to stop"));
- pftbt.handleCancel(true);
- }
- }
- };
+ };
new Thread(endFullBackupRunnable, "end-full-backup").start();
}
@@ -2217,7 +2241,7 @@ public class UserBackupManagerService {
public void restoreWidgetData(String packageName, byte[] widgetData) {
// Apply the restored widget state and generate the ID update for the app
if (DEBUG) {
- Slog.i(TAG, addUserIdToLogMessage(mUserId, "Incorporating restored widget data"));
+ Slog.i(TAG, mLogIdMsg + "Incorporating restored widget data");
}
AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, mUserId);
}
@@ -2235,13 +2259,12 @@ public class UserBackupManagerService {
if (targets == null) {
Slog.w(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "dataChanged but no participant pkg='"
- + packageName
- + "'"
- + " uid="
- + Binder.getCallingUid()));
+ mLogIdMsg
+ + "dataChanged but no participant pkg='"
+ + packageName
+ + "'"
+ + " uid="
+ + Binder.getCallingUid());
return;
}
@@ -2253,10 +2276,7 @@ public class UserBackupManagerService {
BackupRequest req = new BackupRequest(packageName);
if (mPendingBackups.put(packageName, req) == null) {
if (DEBUG) {
- Slog.d(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Now staging backup of " + packageName));
+ Slog.d(TAG, mLogIdMsg + "Now staging backup of " + packageName);
}
// Journal this request in case of crash. The put()
@@ -2268,16 +2288,18 @@ public class UserBackupManagerService {
}
// ...and schedule a backup pass if necessary
- KeyValueBackupJob.schedule(mUserId, mContext,
- /* userBackupManagerService */ this);
+ KeyValueBackupJob.schedule(mUserId, mContext, /* userBackupManagerService */ this);
}
// Note: packageName is currently unused, but may be in the future
private HashSet<String> dataChangedTargets(String packageName) {
// If the caller does not hold the BACKUP permission, it can only request a
// backup of its own data.
- if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
- Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
+ if ((mContext.checkPermission(
+ android.Manifest.permission.BACKUP,
+ Binder.getCallingPid(),
+ Binder.getCallingUid()))
+ == PackageManager.PERMISSION_DENIED) {
synchronized (mBackupParticipants) {
return mBackupParticipants.get(Binder.getCallingUid());
}
@@ -2298,10 +2320,7 @@ public class UserBackupManagerService {
if (mJournal == null) mJournal = DataChangedJournal.newJournal(mJournalDir);
mJournal.addPackage(str);
} catch (IOException e) {
- Slog.e(
- TAG,
- addUserIdToLogMessage(mUserId, "Can't write " + str + " to backup journal"),
- e);
+ Slog.e(TAG, mLogIdMsg + "Can't write " + str + " to backup journal", e);
mJournal = null;
}
}
@@ -2314,31 +2333,28 @@ public class UserBackupManagerService {
if (targets == null) {
Slog.w(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "dataChanged but no participant pkg='"
- + packageName
- + "'"
- + " uid="
- + Binder.getCallingUid()));
+ mLogIdMsg
+ + "dataChanged but no participant pkg='"
+ + packageName
+ + "'"
+ + " uid="
+ + Binder.getCallingUid());
return;
}
- mBackupHandler.post(new Runnable() {
- public void run() {
- dataChangedImpl(packageName, targets);
- }
- });
+ mBackupHandler.post(
+ new Runnable() {
+ public void run() {
+ dataChangedImpl(packageName, targets);
+ }
+ });
}
/** Run an initialize operation for the given transport. */
public void initializeTransports(String[] transportNames, IBackupObserver observer) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "initializeTransport");
- Slog.d(
- TAG,
- addUserIdToLogMessage(
- mUserId, "initializeTransport(): " + Arrays.asList(transportNames)));
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BACKUP, "initializeTransport");
+ Slog.d(TAG, mLogIdMsg + "initializeTransport(): " + Arrays.asList(transportNames));
final long oldId = Binder.clearCallingIdentity();
try {
@@ -2351,32 +2367,23 @@ public class UserBackupManagerService {
}
}
- /**
- * Sets the work profile serial number of the ancestral work profile.
- */
+ /** Sets the work profile serial number of the ancestral work profile. */
public void setAncestralSerialNumber(long ancestralSerialNumber) {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
- "setAncestralSerialNumber");
- Slog.d(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Setting ancestral work profile id to " + ancestralSerialNumber));
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.BACKUP, "setAncestralSerialNumber");
+ Slog.d(TAG, mLogIdMsg + "Setting ancestral work profile id to " + ancestralSerialNumber);
try (RandomAccessFile af =
new RandomAccessFile(getAncestralSerialNumberFile(), /* mode */ "rwd")) {
af.writeLong(ancestralSerialNumber);
} catch (IOException e) {
- Slog.w(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Unable to write to work profile serial mapping file:"),
- e);
+ Slog.w(TAG, mLogIdMsg + "Unable to write to work profile serial mapping file:", e);
}
}
/**
- * Returns the work profile serial number of the ancestral device. This will be set by
- * {@link #setAncestralSerialNumber(long)}. Will return {@code -1} if not set.
+ * Returns the work profile serial number of the ancestral device. This will be set by {@link
+ * #setAncestralSerialNumber(long)}. Will return {@code -1} if not set.
*/
public long getAncestralSerialNumber() {
try (RandomAccessFile af =
@@ -2385,20 +2392,15 @@ public class UserBackupManagerService {
} catch (FileNotFoundException e) {
// It's OK not to have the file present, so we just return -1 to indicate no value.
} catch (IOException e) {
- Slog.w(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Unable to read work profile serial number file:"),
- e);
+ Slog.w(TAG, mLogIdMsg + "Unable to read work profile serial number file:", e);
}
return -1;
}
private File getAncestralSerialNumberFile() {
if (mAncestralSerialNumberFile == null) {
- mAncestralSerialNumberFile = new File(
- UserBackupManagerFiles.getBaseStateDir(getUserId()),
- SERIAL_ID_FILE);
+ mAncestralSerialNumberFile =
+ new File(UserBackupManagerFiles.getBaseStateDir(getUserId()), SERIAL_ID_FILE);
}
return mAncestralSerialNumberFile;
}
@@ -2408,39 +2410,36 @@ public class UserBackupManagerService {
mAncestralSerialNumberFile = ancestralSerialNumberFile;
}
-
/** Clear the given package's backup data from the current transport. */
public void clearBackupData(String transportName, String packageName) {
- Slog.d(TAG, addUserIdToLogMessage(mUserId,
- "clearBackupData() of " + packageName + " on " + transportName));
+ Slog.d(TAG, mLogIdMsg + "clearBackupData() of " + packageName + " on " + transportName);
PackageInfo info;
try {
- info = mPackageManager.getPackageInfoAsUser(packageName,
- PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
+ info =
+ mPackageManager.getPackageInfoAsUser(
+ packageName, PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
} catch (NameNotFoundException e) {
Slog.d(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "No such package '" + packageName + "' - not clearing backup data"));
+ mLogIdMsg + "No such package '" + packageName + "' - not clearing backup data");
return;
}
// If the caller does not hold the BACKUP permission, it can only request a
// wipe of its own backed-up data.
Set<String> apps;
- if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
- Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
+ if ((mContext.checkPermission(
+ android.Manifest.permission.BACKUP,
+ Binder.getCallingPid(),
+ Binder.getCallingUid()))
+ == PackageManager.PERMISSION_DENIED) {
apps = mBackupParticipants.get(Binder.getCallingUid());
} else {
// a caller with full permission can ask to back up any participating app
// !!! TODO: allow data-clear of ANY app?
if (DEBUG) {
- Slog.v(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Privileged caller, allowing clear of other apps"));
+ Slog.v(TAG, mLogIdMsg + "Privileged caller, allowing clear of other apps");
}
apps = mProcessedPackagesJournal.getPackagesCopy();
}
@@ -2448,30 +2447,33 @@ public class UserBackupManagerService {
if (apps.contains(packageName)) {
// found it; fire off the clear request
if (DEBUG) {
- Slog.v(
- TAG,
- addUserIdToLogMessage(mUserId, "Found the app - running clear process"));
+ Slog.v(TAG, mLogIdMsg + "Found the app - running clear process");
}
mBackupHandler.removeMessages(MSG_RETRY_CLEAR);
synchronized (mQueueLock) {
TransportConnection transportConnection =
- mTransportManager
- .getTransportClient(transportName, "BMS.clearBackupData()");
+ mTransportManager.getTransportClient(
+ transportName, "BMS.clearBackupData()");
if (transportConnection == null) {
// transport is currently unregistered -- make sure to retry
- Message msg = mBackupHandler.obtainMessage(MSG_RETRY_CLEAR,
- new ClearRetryParams(transportName, packageName));
+ Message msg =
+ mBackupHandler.obtainMessage(
+ MSG_RETRY_CLEAR,
+ new ClearRetryParams(transportName, packageName));
mBackupHandler.sendMessageDelayed(msg, TRANSPORT_RETRY_INTERVAL);
return;
}
final long oldId = Binder.clearCallingIdentity();
try {
- OnTaskFinishedListener listener = caller -> mTransportManager
- .disposeOfTransportClient(transportConnection, caller);
+ OnTaskFinishedListener listener =
+ caller ->
+ mTransportManager.disposeOfTransportClient(
+ transportConnection, caller);
mWakelock.acquire();
- Message msg = mBackupHandler.obtainMessage(
- MSG_RUN_CLEAR,
- new ClearParams(transportConnection, info, listener));
+ Message msg =
+ mBackupHandler.obtainMessage(
+ MSG_RUN_CLEAR,
+ new ClearParams(transportConnection, info, listener));
mBackupHandler.sendMessage(msg);
} finally {
Binder.restoreCallingIdentity(oldId);
@@ -2492,31 +2494,24 @@ public class UserBackupManagerService {
final PowerSaveState result =
mPowerManager.getPowerSaveState(ServiceType.KEYVALUE_BACKUP);
if (result.batterySaverEnabled) {
- Slog.d(TAG, addUserIdToLogMessage(mUserId,
- "Not running backup while in battery save mode"));
+ Slog.d(TAG, mLogIdMsg + "Not running backup while in battery save mode");
// Try again in several hours.
- KeyValueBackupJob.schedule(mUserId, mContext,
- /* userBackupManagerService */ this);
+ KeyValueBackupJob.schedule(mUserId, mContext, /* userBackupManagerService */ this);
} else {
- Slog.d(TAG, addUserIdToLogMessage(mUserId, "Scheduling immediate backup pass"));
+ Slog.d(TAG, mLogIdMsg + "Scheduling immediate backup pass");
synchronized (getQueueLock()) {
if (getPendingInits().size() > 0) {
// If there are pending init operations, we process those and then settle
// into the usual periodic backup schedule.
if (DEBUG) {
- Slog.v(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Init pending at scheduled backup"));
+ Slog.v(TAG, mLogIdMsg + "Init pending at scheduled backup");
}
try {
getAlarmManager().cancel(mRunInitIntent);
mRunInitIntent.send();
} catch (PendingIntent.CanceledException ce) {
- Slog.w(
- TAG,
- addUserIdToLogMessage(mUserId, "Run init intent cancelled"));
+ Slog.w(TAG, mLogIdMsg + "Run init intent cancelled");
}
return;
}
@@ -2526,8 +2521,11 @@ public class UserBackupManagerService {
if (!isEnabled() || !isSetupComplete()) {
Slog.w(
TAG,
- addUserIdToLogMessage(mUserId, "Backup pass but enabled=" + isEnabled()
- + " setupComplete=" + isSetupComplete()));
+ mLogIdMsg
+ + "Backup pass but enabled="
+ + isEnabled()
+ + " setupComplete="
+ + isSetupComplete());
return;
}
@@ -2548,9 +2546,17 @@ public class UserBackupManagerService {
* return to the caller until the backup has been completed. It requires on-screen confirmation
* by the user.
*/
- public void adbBackup(ParcelFileDescriptor fd, boolean includeApks,
- boolean includeObbs, boolean includeShared, boolean doWidgets, boolean doAllApps,
- boolean includeSystem, boolean compress, boolean doKeyValue, String[] pkgList) {
+ public void adbBackup(
+ ParcelFileDescriptor fd,
+ boolean includeApks,
+ boolean includeObbs,
+ boolean includeShared,
+ boolean doWidgets,
+ boolean doAllApps,
+ boolean includeSystem,
+ boolean compress,
+ boolean doKeyValue,
+ String[] pkgList) {
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "adbBackup");
final int callingUserHandle = UserHandle.getCallingUserId();
@@ -2574,47 +2580,66 @@ public class UserBackupManagerService {
final long oldId = Binder.clearCallingIdentity();
try {
if (!mSetupComplete) {
- Slog.i(TAG, addUserIdToLogMessage(mUserId, "Backup not supported before setup"));
+ Slog.i(TAG, mLogIdMsg + "Backup not supported before setup");
return;
}
- Slog.d(TAG, addUserIdToLogMessage(mUserId,
- "Requesting backup: apks=" + includeApks + " obb=" + includeObbs + " shared="
- + includeShared + " all=" + doAllApps + " system=" + includeSystem
- + " includekeyvalue=" + doKeyValue + " pkgs=" + Arrays.toString(
- pkgList)));
- Slog.i(TAG, addUserIdToLogMessage(mUserId, "Beginning adb backup..."));
-
- BackupEligibilityRules eligibilityRules = getEligibilityRulesForOperation(
- BackupDestination.ADB_BACKUP);
- AdbBackupParams params = new AdbBackupParams(fd, includeApks, includeObbs,
- includeShared, doWidgets, doAllApps, includeSystem, compress, doKeyValue,
- pkgList, eligibilityRules);
+ Slog.d(
+ TAG,
+ mLogIdMsg
+ + "Requesting backup: apks="
+ + includeApks
+ + " obb="
+ + includeObbs
+ + " shared="
+ + includeShared
+ + " all="
+ + doAllApps
+ + " system="
+ + includeSystem
+ + " includekeyvalue="
+ + doKeyValue
+ + " pkgs="
+ + Arrays.toString(pkgList));
+ Slog.i(TAG, mLogIdMsg + "Beginning adb backup...");
+
+ BackupEligibilityRules eligibilityRules =
+ getEligibilityRulesForOperation(BackupDestination.ADB_BACKUP);
+ AdbBackupParams params =
+ new AdbBackupParams(
+ fd,
+ includeApks,
+ includeObbs,
+ includeShared,
+ doWidgets,
+ doAllApps,
+ includeSystem,
+ compress,
+ doKeyValue,
+ pkgList,
+ eligibilityRules);
final int token = generateRandomIntegerToken();
synchronized (mAdbBackupRestoreConfirmations) {
mAdbBackupRestoreConfirmations.put(token, params);
}
// start up the confirmation UI
- Slog.d(TAG, addUserIdToLogMessage(mUserId, "Starting backup confirmation UI"));
+ Slog.d(TAG, mLogIdMsg + "Starting backup confirmation UI");
if (!startConfirmationUi(token, FullBackup.FULL_BACKUP_INTENT_ACTION)) {
- Slog.e(
- TAG,
- addUserIdToLogMessage(mUserId, "Unable to launch backup confirmation UI"));
+ Slog.e(TAG, mLogIdMsg + "Unable to launch backup confirmation UI");
mAdbBackupRestoreConfirmations.delete(token);
return;
}
// make sure the screen is lit for the user interaction
- mPowerManager.userActivity(SystemClock.uptimeMillis(),
- PowerManager.USER_ACTIVITY_EVENT_OTHER,
- 0);
+ mPowerManager.userActivity(
+ SystemClock.uptimeMillis(), PowerManager.USER_ACTIVITY_EVENT_OTHER, 0);
// start the confirmation countdown
startConfirmationTimeout(token, params);
// wait for the backup to be performed
- Slog.d(TAG, addUserIdToLogMessage(mUserId, "Waiting for backup completion..."));
+ Slog.d(TAG, mLogIdMsg + "Waiting for backup completion...");
waitForCompletion(params);
} finally {
try {
@@ -2622,19 +2647,17 @@ public class UserBackupManagerService {
} catch (IOException e) {
Slog.e(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "IO error closing output for adb backup: " + e.getMessage()));
+ mLogIdMsg + "IO error closing output for adb backup: " + e.getMessage());
}
Binder.restoreCallingIdentity(oldId);
- Slog.d(TAG, addUserIdToLogMessage(mUserId, "Adb backup processing complete."));
+ Slog.d(TAG, mLogIdMsg + "Adb backup processing complete.");
}
}
/** Run a full backup pass for the given packages. Used by 'adb shell bmgr'. */
public void fullTransportBackup(String[] pkgNames) {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
- "fullTransportBackup");
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.BACKUP, "fullTransportBackup");
final int callingUserHandle = UserHandle.getCallingUserId();
// TODO: http://b/22388012
if (callingUserHandle != UserHandle.USER_SYSTEM) {
@@ -2643,30 +2666,27 @@ public class UserBackupManagerService {
String transportName = mTransportManager.getCurrentTransportName();
if (!fullBackupAllowable(transportName)) {
- Slog.i(
- TAG,
- addUserIdToLogMessage(
- mUserId,
- "Full backup not currently possible -- key/value backup not yet run?"));
+ Slog.i(TAG, mLogIdMsg + "Full backup not possible. Key/value backup not yet run?");
} else {
- Slog.d(TAG, addUserIdToLogMessage(mUserId, "fullTransportBackup()"));
+ Slog.d(TAG, mLogIdMsg + "fullTransportBackup()");
final long oldId = Binder.clearCallingIdentity();
try {
CountDownLatch latch = new CountDownLatch(1);
- Runnable task = PerformFullTransportBackupTask.newWithCurrentTransport(
- this,
- mOperationStorage,
- /* observer */ null,
- pkgNames,
- /* updateSchedule */ false,
- /* runningJob */ null,
- latch,
- /* backupObserver */ null,
- /* monitor */ null,
- /* userInitiated */ false,
- "BMS.fullTransportBackup()",
- getEligibilityRulesForOperation(BackupDestination.CLOUD));
+ Runnable task =
+ PerformFullTransportBackupTask.newWithCurrentTransport(
+ this,
+ mOperationStorage,
+ /* observer */ null,
+ pkgNames,
+ /* updateSchedule */ false,
+ /* runningJob */ null,
+ latch,
+ /* backupObserver */ null,
+ /* monitor */ null,
+ /* userInitiated */ false,
+ "BMS.fullTransportBackup()",
+ getEligibilityRulesForOperation(BackupDestination.CLOUD));
// Acquiring wakelock for PerformFullTransportBackupTask before its start.
mWakelock.acquire();
(new Thread(task, "full-transport-master")).start();
@@ -2692,7 +2712,7 @@ public class UserBackupManagerService {
}
}
- Slog.d(TAG, addUserIdToLogMessage(mUserId, "Done with full transport backup."));
+ Slog.d(TAG, mLogIdMsg + "Done with full transport backup.");
}
/**
@@ -2711,13 +2731,11 @@ public class UserBackupManagerService {
try {
if (!mSetupComplete) {
- Slog.i(
- TAG,
- addUserIdToLogMessage(mUserId, "Full restore not permitted before setup"));
+ Slog.i(TAG, mLogIdMsg + "Full restore not permitted before setup");
return;
}
- Slog.i(TAG, addUserIdToLogMessage(mUserId, "Beginning restore..."));
+ Slog.i(TAG, mLogIdMsg + "Beginning restore...");
AdbRestoreParams params = new AdbRestoreParams(fd);
final int token = generateRandomIntegerToken();
@@ -2726,38 +2744,31 @@ public class UserBackupManagerService {
}
// start up the confirmation UI
- Slog.d(TAG, addUserIdToLogMessage(mUserId,
- "Starting restore confirmation UI, token=" + token));
+ Slog.d(TAG, mLogIdMsg + "Starting restore confirmation UI, token=" + token);
if (!startConfirmationUi(token, FullBackup.FULL_RESTORE_INTENT_ACTION)) {
- Slog.e(
- TAG,
- addUserIdToLogMessage(mUserId, "Unable to launch restore confirmation"));
+ Slog.e(TAG, mLogIdMsg + "Unable to launch restore confirmation");
mAdbBackupRestoreConfirmations.delete(token);
return;
}
// make sure the screen is lit for the user interaction
- mPowerManager.userActivity(SystemClock.uptimeMillis(),
- PowerManager.USER_ACTIVITY_EVENT_OTHER,
- 0);
+ mPowerManager.userActivity(
+ SystemClock.uptimeMillis(), PowerManager.USER_ACTIVITY_EVENT_OTHER, 0);
// start the confirmation countdown
startConfirmationTimeout(token, params);
// wait for the restore to be performed
- Slog.d(TAG, addUserIdToLogMessage(mUserId, "Waiting for restore completion..."));
+ Slog.d(TAG, mLogIdMsg + "Waiting for restore completion...");
waitForCompletion(params);
} finally {
try {
fd.close();
} catch (IOException e) {
- Slog.w(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Error trying to close fd after adb restore: " + e));
+ Slog.w(TAG, mLogIdMsg + "Error trying to close fd after adb restore: " + e);
}
Binder.restoreCallingIdentity(oldId);
- Slog.i(TAG, addUserIdToLogMessage(mUserId, "adb restore processing complete."));
+ Slog.i(TAG, mLogIdMsg + "adb restore processing complete.");
}
}
@@ -2766,13 +2777,14 @@ public class UserBackupManagerService {
* to the backup agent during restore.
*/
public void excludeKeysFromRestore(String packageName, List<String> keys) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "excludeKeysFromRestore");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BACKUP, "excludeKeysFromRestore");
mBackupPreferences.addExcludedKeys(packageName, keys);
}
- public void reportDelayedRestoreResult(String packageName,
- List<BackupRestoreEventLogger.DataTypeResult> results) {
+ /** See {@link BackupManager#reportDelayedRestoreResult(BackupRestoreEventLogger)}. */
+ public void reportDelayedRestoreResult(
+ String packageName, List<BackupRestoreEventLogger.DataTypeResult> results) {
String transport = mTransportManager.getCurrentTransportName();
if (transport == null) {
Slog.w(TAG, "Failed to send delayed restore logs as no transport selected");
@@ -2781,26 +2793,34 @@ public class UserBackupManagerService {
TransportConnection transportConnection = null;
try {
- PackageInfo packageInfo = getPackageManager().getPackageInfoAsUser(packageName,
- PackageManager.PackageInfoFlags.of(/* value */ 0), getUserId());
+ PackageInfo packageInfo =
+ getPackageManager()
+ .getPackageInfoAsUser(
+ packageName,
+ PackageManager.PackageInfoFlags.of(/* value */ 0),
+ getUserId());
- transportConnection = mTransportManager.getTransportClientOrThrow(
- transport, /* caller */"BMS.reportDelayedRestoreResult");
- BackupTransportClient transportClient = transportConnection.connectOrThrow(
- /* caller */ "BMS.reportDelayedRestoreResult");
+ transportConnection =
+ mTransportManager.getTransportClientOrThrow(
+ transport, /* caller */ "BMS.reportDelayedRestoreResult");
+ BackupTransportClient transportClient =
+ transportConnection.connectOrThrow(
+ /* caller */ "BMS.reportDelayedRestoreResult");
IBackupManagerMonitor monitor = transportClient.getBackupManagerMonitor();
- BackupManagerMonitorEventSender mBackupManagerMonitorEventSender =
+ BackupManagerMonitorEventSender mBackupManagerMonitorEventSender =
getBMMEventSender(monitor);
- mBackupManagerMonitorEventSender.sendAgentLoggingResults(packageInfo, results,
- BackupAnnotations.OperationType.RESTORE);
- } catch (NameNotFoundException | TransportNotAvailableException
- | TransportNotRegisteredException | RemoteException e) {
+ mBackupManagerMonitorEventSender.sendAgentLoggingResults(
+ packageInfo, results, BackupAnnotations.OperationType.RESTORE);
+ } catch (NameNotFoundException
+ | TransportNotAvailableException
+ | TransportNotRegisteredException
+ | RemoteException e) {
Slog.w(TAG, "Failed to send delayed restore logs: " + e);
} finally {
if (transportConnection != null) {
- mTransportManager.disposeOfTransportClient(transportConnection,
- /* caller */"BMS.reportDelayedRestoreResult");
+ mTransportManager.disposeOfTransportClient(
+ transportConnection, /* caller */ "BMS.reportDelayedRestoreResult");
}
}
}
@@ -2808,7 +2828,8 @@ public class UserBackupManagerService {
private boolean startConfirmationUi(int token, String action) {
try {
Intent confIntent = new Intent(action);
- confIntent.setClassName("com.android.backupconfirm",
+ confIntent.setClassName(
+ "com.android.backupconfirm",
"com.android.backupconfirm.BackupRestoreConfirmation");
confIntent.putExtra(FullBackup.CONF_TOKEN_INTENT_EXTRA, token);
confIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
@@ -2821,11 +2842,14 @@ public class UserBackupManagerService {
private void startConfirmationTimeout(int token, AdbParams params) {
if (DEBUG) {
- Slog.d(TAG, addUserIdToLogMessage(mUserId, "Posting conf timeout msg after "
- + TIMEOUT_FULL_CONFIRMATION + " millis"));
+ Slog.d(
+ TAG,
+ mLogIdMsg
+ + "Posting conf timeout msg after "
+ + TIMEOUT_FULL_CONFIRMATION
+ + " millis");
}
- Message msg = mBackupHandler.obtainMessage(MSG_FULL_CONFIRMATION_TIMEOUT,
- token, 0, params);
+ Message msg = mBackupHandler.obtainMessage(MSG_FULL_CONFIRMATION_TIMEOUT, token, 0, params);
mBackupHandler.sendMessageDelayed(msg, TIMEOUT_FULL_CONFIRMATION);
}
@@ -2834,7 +2858,9 @@ public class UserBackupManagerService {
while (!params.latch.get()) {
try {
params.latch.wait();
- } catch (InterruptedException e) { /* never interrupted */ }
+ } catch (InterruptedException e) {
+ /* never interrupted */
+ }
}
}
}
@@ -2851,15 +2877,20 @@ public class UserBackupManagerService {
* Confirm that the previously-requested full backup/restore operation can proceed. This is used
* to require a user-facing disclosure about the operation.
*/
- public void acknowledgeAdbBackupOrRestore(int token, boolean allow,
- String curPassword, String encPpassword, IFullBackupRestoreObserver observer) {
- Slog.d(TAG, addUserIdToLogMessage(mUserId,
- "acknowledgeAdbBackupOrRestore : token=" + token + " allow=" + allow));
+ public void acknowledgeAdbBackupOrRestore(
+ int token,
+ boolean allow,
+ String curPassword,
+ String encPpassword,
+ IFullBackupRestoreObserver observer) {
+ Slog.d(
+ TAG,
+ mLogIdMsg + "acknowledgeAdbBackupOrRestore : token=" + token + " allow=" + allow);
// TODO: possibly require not just this signature-only permission, but even
// require that the specific designated confirmation-UI app uid is the caller?
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
- "acknowledgeAdbBackupOrRestore");
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.BACKUP, "acknowledgeAdbBackupOrRestore");
final long oldId = Binder.clearCallingIdentity();
try {
@@ -2872,9 +2903,10 @@ public class UserBackupManagerService {
mAdbBackupRestoreConfirmations.delete(token);
if (allow) {
- final int verb = params instanceof AdbBackupParams
- ? MSG_RUN_ADB_BACKUP
- : MSG_RUN_ADB_RESTORE;
+ final int verb =
+ params instanceof AdbBackupParams
+ ? MSG_RUN_ADB_BACKUP
+ : MSG_RUN_ADB_RESTORE;
params.observer = observer;
params.curPassword = curPassword;
@@ -2882,28 +2914,20 @@ public class UserBackupManagerService {
params.encryptPassword = encPpassword;
if (DEBUG) {
- Slog.d(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Sending conf message with verb " + verb));
+ Slog.d(TAG, mLogIdMsg + "Sending conf message with verb " + verb);
}
mWakelock.acquire();
Message msg = mBackupHandler.obtainMessage(verb, params);
mBackupHandler.sendMessage(msg);
} else {
- Slog.w(
- TAG,
- addUserIdToLogMessage(
- mUserId, "User rejected full backup/restore operation"));
+ Slog.w(TAG, mLogIdMsg + "User rejected full backup/restore operation");
// indicate completion without having actually transferred any data
signalAdbBackupRestoreCompletion(params);
}
} else {
Slog.w(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "Attempted to ack full backup/restore with invalid token"));
+ mLogIdMsg + "Attempted to ack full backup/restore with invalid token");
}
}
} finally {
@@ -2922,10 +2946,10 @@ public class UserBackupManagerService {
}
private void setBackupEnabled(boolean enable, boolean persistToDisk) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "setBackupEnabled");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BACKUP, "setBackupEnabled");
- Slog.i(TAG, addUserIdToLogMessage(mUserId, "Backup enabled => " + enable));
+ Slog.i(TAG, mLogIdMsg + "Backup enabled => " + enable);
final long oldId = Binder.clearCallingIdentity();
try {
@@ -2944,23 +2968,25 @@ public class UserBackupManagerService {
}
synchronized void setFrameworkSchedulingEnabled(boolean isEnabled) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "setFrameworkSchedulingEnabled");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BACKUP, "setFrameworkSchedulingEnabled");
boolean wasEnabled = isFrameworkSchedulingEnabled();
if (wasEnabled == isEnabled) {
return;
}
- Slog.i(TAG, addUserIdToLogMessage(mUserId,
- (isEnabled ? "Enabling" : "Disabling") + " backup scheduling"));
+ Slog.i(TAG, mLogIdMsg + (isEnabled ? "Enabling" : "Disabling") + " backup scheduling");
final long oldId = Binder.clearCallingIdentity();
try {
// TODO(b/264889098): Consider at a later point if we should us a sentinel file as
// setBackupEnabled.
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.BACKUP_SCHEDULING_ENABLED, isEnabled ? 1 : 0, mUserId);
+ Settings.Secure.putIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.BACKUP_SCHEDULING_ENABLED,
+ isEnabled ? 1 : 0,
+ mUserId);
if (!isEnabled) {
KeyValueBackupJob.cancel(mUserId, mContext);
@@ -2977,8 +3003,12 @@ public class UserBackupManagerService {
synchronized boolean isFrameworkSchedulingEnabled() {
// By default scheduling is enabled
final int defaultSetting = 1;
- int isEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.BACKUP_SCHEDULING_ENABLED, defaultSetting, mUserId);
+ int isEnabled =
+ Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.BACKUP_SCHEDULING_ENABLED,
+ defaultSetting,
+ mUserId);
return isEnabled == 1;
}
@@ -2992,7 +3022,7 @@ public class UserBackupManagerService {
} else if (!enable) {
// No longer enabled, so stop running backups
if (DEBUG) {
- Slog.i(TAG, addUserIdToLogMessage(mUserId, "Opting out of backup"));
+ Slog.i(TAG, mLogIdMsg + "Opting out of backup");
}
KeyValueBackupJob.cancel(mUserId, mContext);
@@ -3012,11 +3042,7 @@ public class UserBackupManagerService {
dirName = mTransportManager.getTransportDirName(name);
} catch (TransportNotRegisteredException e) {
// Should never happen
- Slog.e(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Unexpected unregistered transport"),
- e);
+ Slog.e(TAG, mLogIdMsg + "Unexpected unregistered transport", e);
return;
}
transportNames.add(name);
@@ -3025,13 +3051,10 @@ public class UserBackupManagerService {
// build the set of transports for which we are posting an init
for (int i = 0; i < transportNames.size(); i++) {
- recordInitPending(
- true,
- transportNames.get(i),
- transportDirNames.get(i));
+ recordInitPending(true, transportNames.get(i), transportDirNames.get(i));
}
- mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
- mRunInitIntent);
+ mAlarmManager.set(
+ AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), mRunInitIntent);
}
}
}
@@ -3049,16 +3072,19 @@ public class UserBackupManagerService {
/** Enable/disable automatic restore of app data at install time. */
public void setAutoRestore(boolean doAutoRestore) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "setAutoRestore");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BACKUP, "setAutoRestore");
- Slog.i(TAG, addUserIdToLogMessage(mUserId, "Auto restore => " + doAutoRestore));
+ Slog.i(TAG, mLogIdMsg + "Auto restore => " + doAutoRestore);
final long oldId = Binder.clearCallingIdentity();
try {
synchronized (this) {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0, mUserId);
+ Settings.Secure.putIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.BACKUP_AUTO_RESTORE,
+ doAutoRestore ? 1 : 0,
+ mUserId);
mAutoRestore = doAutoRestore;
}
} finally {
@@ -3068,21 +3094,18 @@ public class UserBackupManagerService {
/** Report whether the backup mechanism is currently enabled. */
public boolean isBackupEnabled() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "isBackupEnabled");
- return mEnabled; // no need to synchronize just to read it
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BACKUP, "isBackupEnabled");
+ return mEnabled; // no need to synchronize just to read it
}
/** Report the name of the currently active transport. */
public String getCurrentTransport() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "getCurrentTransport");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BACKUP, "getCurrentTransport");
String currentTransport = mTransportManager.getCurrentTransportName();
if (DEBUG) {
- Slog.v(
- TAG,
- addUserIdToLogMessage(
- mUserId, "... getCurrentTransport() returning " + currentTransport));
+ Slog.v(TAG, mLogIdMsg + "... getCurrentTransport() returning " + currentTransport);
}
return currentTransport;
}
@@ -3107,16 +3130,16 @@ public class UserBackupManagerService {
/** Report all known, available backup transports by name. */
public String[] listAllTransports() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "listAllTransports");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BACKUP, "listAllTransports");
return mTransportManager.getRegisteredTransportNames();
}
/** Report all known, available backup transports by component. */
public ComponentName[] listAllTransportComponents() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "listAllTransportComponents");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BACKUP, "listAllTransportComponents");
return mTransportManager.getRegisteredTransportComponents();
}
@@ -3129,18 +3152,17 @@ public class UserBackupManagerService {
* @param transportComponent The identity of the transport being described.
* @param name A {@link String} with the new name for the transport. This is NOT for
* identification. MUST NOT be {@code null}.
- * @param configurationIntent An {@link Intent} that can be passed to
- * {@link Context#startActivity} in order to launch the transport's configuration UI. It may
- * be {@code null} if the transport does not offer any user-facing configuration UI.
+ * @param configurationIntent An {@link Intent} that can be passed to {@link
+ * Context#startActivity} in order to launch the transport's configuration UI. It may be
+ * {@code null} if the transport does not offer any user-facing configuration UI.
* @param currentDestinationString A {@link String} describing the destination to which the
* transport is currently sending data. MUST NOT be {@code null}.
- * @param dataManagementIntent An {@link Intent} that can be passed to
- * {@link Context#startActivity} in order to launch the transport's data-management UI. It
- * may be {@code null} if the transport does not offer any user-facing data
- * management UI.
+ * @param dataManagementIntent An {@link Intent} that can be passed to {@link
+ * Context#startActivity} in order to launch the transport's data-management UI. It may be
+ * {@code null} if the transport does not offer any user-facing data management UI.
* @param dataManagementLabel A {@link CharSequence} to be used as the label for the transport's
- * data management affordance. This MUST be {@code null} when dataManagementIntent is
- * {@code null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
+ * data management affordance. This MUST be {@code null} when dataManagementIntent is {@code
+ * null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
* @throws SecurityException If the UID of the calling process differs from the package UID of
* {@code transportComponent} or if the caller does NOT have BACKUP permission.
*/
@@ -3175,8 +3197,7 @@ public class UserBackupManagerService {
Objects.requireNonNull(transportComponent, "transportComponent can't be null");
Objects.requireNonNull(name, "name can't be null");
- Objects.requireNonNull(
- currentDestinationString, "currentDestinationString can't be null");
+ Objects.requireNonNull(currentDestinationString, "currentDestinationString can't be null");
Preconditions.checkArgument(
(dataManagementIntent == null) == (dataManagementLabel == null),
"dataManagementLabel should be null iff dataManagementIntent is null");
@@ -3211,7 +3232,7 @@ public class UserBackupManagerService {
* selected transport. Returns {@code null} if the transport is not registered.
*
* @deprecated Use {@link #selectBackupTransportAsync(ComponentName,
- * ISelectBackupTransportCallback)} instead.
+ * ISelectBackupTransportCallback)} instead.
*/
@Deprecated
@Nullable
@@ -3224,11 +3245,10 @@ public class UserBackupManagerService {
if (!mTransportManager.isTransportRegistered(transportName)) {
Slog.d(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "Could not select transport "
- + transportName
- + ", as the transport is not registered."));
+ mLogIdMsg
+ + "Could not select transport "
+ + transportName
+ + ", as the transport is not registered.");
return null;
}
@@ -3236,12 +3256,11 @@ public class UserBackupManagerService {
updateStateForTransport(transportName);
Slog.d(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "selectBackupTransport(transport = "
- + transportName
- + "): previous transport = "
- + previousTransportName));
+ mLogIdMsg
+ + "selectBackupTransport(transport = "
+ + transportName
+ + "): previous transport = "
+ + previousTransportName);
return previousTransportName;
} finally {
Binder.restoreCallingIdentity(oldId);
@@ -3262,9 +3281,7 @@ public class UserBackupManagerService {
String transportString = transportComponent.flattenToShortString();
Slog.d(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "selectBackupTransportAsync(transport = " + transportString + ")"));
+ mLogIdMsg + "selectBackupTransportAsync(transport = " + transportString + ")");
mBackupHandler.post(
() -> {
String transportName = null;
@@ -3276,10 +3293,7 @@ public class UserBackupManagerService {
mTransportManager.getTransportName(transportComponent);
updateStateForTransport(transportName);
} catch (TransportNotRegisteredException e) {
- Slog.e(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Transport got unregistered"));
+ Slog.e(TAG, mLogIdMsg + "Transport got unregistered");
result = BackupManager.ERROR_TRANSPORT_UNAVAILABLE;
}
}
@@ -3293,10 +3307,9 @@ public class UserBackupManagerService {
} catch (RemoteException e) {
Slog.e(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "ISelectBackupTransportCallback listener not"
- + " available"));
+ mLogIdMsg
+ + "ISelectBackupTransportCallback listener not"
+ + " available");
}
});
} finally {
@@ -3306,8 +3319,11 @@ public class UserBackupManagerService {
private void updateStateForTransport(String newTransportName) {
// Publish the name change
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
- Settings.Secure.BACKUP_TRANSPORT, newTransportName, mUserId);
+ Settings.Secure.putStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.BACKUP_TRANSPORT,
+ newTransportName,
+ mUserId);
// And update our current-dataset bookkeeping
String callerLogString = "BMS.updateStateForTransport()";
@@ -3315,8 +3331,8 @@ public class UserBackupManagerService {
mTransportManager.getTransportClient(newTransportName, callerLogString);
if (transportConnection != null) {
try {
- BackupTransportClient transport = transportConnection.connectOrThrow(
- callerLogString);
+ BackupTransportClient transport =
+ transportConnection.connectOrThrow(callerLogString);
mCurrentToken = transport.getCurrentRestoreSet();
} catch (Exception e) {
// Oops. We can't know the current dataset token, so reset and figure it out
@@ -3324,21 +3340,19 @@ public class UserBackupManagerService {
mCurrentToken = 0;
Slog.w(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "Transport "
- + newTransportName
- + " not available: current token = 0"));
+ mLogIdMsg
+ + "Transport "
+ + newTransportName
+ + " not available: current token = 0");
}
mTransportManager.disposeOfTransportClient(transportConnection, callerLogString);
} else {
Slog.w(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "Transport "
- + newTransportName
- + " not registered: current token = 0"));
+ mLogIdMsg
+ + "Transport "
+ + newTransportName
+ + " not registered: current token = 0");
// The named transport isn't registered, so we can't know what its current dataset token
// is. Reset as above.
mCurrentToken = 0;
@@ -3351,24 +3365,20 @@ public class UserBackupManagerService {
* returns {@code null}.
*/
public Intent getConfigurationIntent(String transportName) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "getConfigurationIntent");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BACKUP, "getConfigurationIntent");
try {
Intent intent = mTransportManager.getTransportConfigurationIntent(transportName);
if (DEBUG) {
- Slog.d(
- TAG,
- addUserIdToLogMessage(
- mUserId, "getConfigurationIntent() returning intent " + intent));
+ Slog.d(TAG, mLogIdMsg + "getConfigurationIntent() returning intent " + intent);
}
return intent;
} catch (TransportNotRegisteredException e) {
Slog.e(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "Unable to get configuration intent from transport: "
- + e.getMessage()));
+ mLogIdMsg
+ + "Unable to get configuration intent from transport: "
+ + e.getMessage());
return null;
}
}
@@ -3389,42 +3399,36 @@ public class UserBackupManagerService {
try {
String string = mTransportManager.getTransportCurrentDestinationString(transportName);
if (DEBUG) {
- Slog.d(
- TAG,
- addUserIdToLogMessage(
- mUserId, "getDestinationString() returning " + string));
+ Slog.d(TAG, mLogIdMsg + "getDestinationString() returning " + string);
}
return string;
} catch (TransportNotRegisteredException e) {
Slog.e(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "Unable to get destination string from transport: " + e.getMessage()));
+ mLogIdMsg
+ + "Unable to get destination string from transport: "
+ + e.getMessage());
return null;
}
}
/** Supply the manage-data intent for the given transport. */
public Intent getDataManagementIntent(String transportName) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "getDataManagementIntent");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BACKUP, "getDataManagementIntent");
try {
Intent intent = mTransportManager.getTransportDataManagementIntent(transportName);
if (DEBUG) {
- Slog.d(
- TAG,
- addUserIdToLogMessage(
- mUserId, "getDataManagementIntent() returning intent " + intent));
+ Slog.d(TAG, mLogIdMsg + "getDataManagementIntent() returning intent " + intent);
}
return intent;
} catch (TransportNotRegisteredException e) {
Slog.e(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "Unable to get management intent from transport: " + e.getMessage()));
+ mLogIdMsg
+ + "Unable to get management intent from transport: "
+ + e.getMessage());
return null;
}
}
@@ -3434,24 +3438,19 @@ public class UserBackupManagerService {
* transport.
*/
public CharSequence getDataManagementLabel(String transportName) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "getDataManagementLabel");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BACKUP, "getDataManagementLabel");
try {
CharSequence label = mTransportManager.getTransportDataManagementLabel(transportName);
if (DEBUG) {
- Slog.d(
- TAG,
- addUserIdToLogMessage(
- mUserId, "getDataManagementLabel() returning " + label));
+ Slog.d(TAG, mLogIdMsg + "getDataManagementLabel() returning " + label);
}
return label;
} catch (TransportNotRegisteredException e) {
Slog.e(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "Unable to get management label from transport: " + e.getMessage()));
+ mLogIdMsg + "Unable to get management label from transport: " + e.getMessage());
return null;
}
}
@@ -3464,57 +3463,64 @@ public class UserBackupManagerService {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
Slog.w(
TAG,
- addUserIdToLogMessage(
- mUserId,
- "Non-system process uid="
- + Binder.getCallingUid()
- + " attemping install-time restore"));
+ mLogIdMsg
+ + "Non-system process uid="
+ + Binder.getCallingUid()
+ + " attemping install-time restore");
return;
}
boolean skip = false;
long restoreSet = getAvailableRestoreToken(packageName);
- Slog.d(TAG, addUserIdToLogMessage(mUserId,
- "restoreAtInstall pkg=" + packageName + " token=" + Integer.toHexString(token)
- + " restoreSet=" + Long.toHexString(restoreSet)));
+ Slog.d(
+ TAG,
+ mLogIdMsg
+ + "restoreAtInstall pkg="
+ + packageName
+ + " token="
+ + Integer.toHexString(token)
+ + " restoreSet="
+ + Long.toHexString(restoreSet));
if (restoreSet == 0) {
- if (DEBUG) Slog.i(TAG, addUserIdToLogMessage(mUserId, "No restore set"));
+ if (DEBUG) Slog.i(TAG, mLogIdMsg + "No restore set");
skip = true;
}
- BackupManagerMonitorEventSender mBMMEventSender =
- getBMMEventSender(/*monitor=*/ null);
+ BackupManagerMonitorEventSender mBMMEventSender = getBMMEventSender(/* monitor= */ null);
PackageInfo packageInfo = getPackageInfoForBMMLogging(packageName);
TransportConnection transportConnection =
mTransportManager.getCurrentTransportClient("BMS.restoreAtInstall()");
if (transportConnection == null) {
- Slog.w(TAG, addUserIdToLogMessage(mUserId, "No transport client"));
+ Slog.w(TAG, mLogIdMsg + "No transport client");
skip = true;
} else if (Flags.enableIncreasedBmmLoggingForRestoreAtInstall()) {
try {
- BackupTransportClient transportClient = transportConnection.connectOrThrow(
- "BMS.restoreAtInstall");
+ BackupTransportClient transportClient =
+ transportConnection.connectOrThrow("BMS.restoreAtInstall");
mBMMEventSender.setMonitor(transportClient.getBackupManagerMonitor());
} catch (TransportNotAvailableException | RemoteException e) {
mBMMEventSender.monitorEvent(
- BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_IS_NULL, packageInfo,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null);
+ BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_IS_NULL,
+ packageInfo,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
+ null);
}
}
if (Flags.enableIncreasedBmmLoggingForRestoreAtInstall()) {
mBMMEventSender.monitorEvent(
- BackupManagerMonitor.LOG_EVENT_ID_RESTORE_AT_INSTALL_INVOKED, packageInfo,
+ BackupManagerMonitor.LOG_EVENT_ID_RESTORE_AT_INSTALL_INVOKED,
+ packageInfo,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- mBMMEventSender.putMonitoringExtra(/*extras=*/null,
+ mBMMEventSender.putMonitoringExtra(
+ /* extras= */ null,
BackupManagerMonitor.EXTRA_LOG_OPERATION_TYPE,
BackupAnnotations.OperationType.RESTORE));
}
if (!mAutoRestore) {
- Slog.w(TAG,
- addUserIdToLogMessage(mUserId, "Non-restorable state: auto=" + mAutoRestore));
+ Slog.w(TAG, mLogIdMsg + "Non-restorable state: auto=" + mAutoRestore);
skip = true;
}
@@ -3526,15 +3532,14 @@ public class UserBackupManagerService {
mWakelock.acquire();
- OnTaskFinishedListener listener = caller -> {
- mTransportManager.disposeOfTransportClient(transportConnection, caller);
- mWakelock.release();
- };
+ OnTaskFinishedListener listener =
+ caller -> {
+ mTransportManager.disposeOfTransportClient(transportConnection, caller);
+ mWakelock.release();
+ };
if (DEBUG) {
- Slog.d(
- TAG,
- addUserIdToLogMessage(mUserId, "Restore at install of " + packageName));
+ Slog.d(TAG, mLogIdMsg + "Restore at install of " + packageName);
}
Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
msg.obj =
@@ -3550,10 +3555,7 @@ public class UserBackupManagerService {
mBackupHandler.sendMessage(msg);
} catch (Exception e) {
// Calling into the transport broke; back off and proceed with the installation.
- Slog.e(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Unable to contact transport: " + e.getMessage()));
+ Slog.e(TAG, mLogIdMsg + "Unable to contact transport: " + e.getMessage());
skip = true;
}
}
@@ -3563,9 +3565,11 @@ public class UserBackupManagerService {
if (Flags.enableIncreasedBmmLoggingForRestoreAtInstall()) {
mBMMEventSender.monitorEvent(
- BackupManagerMonitor.LOG_EVENT_ID_SKIP_RESTORE_AT_INSTALL, packageInfo,
+ BackupManagerMonitor.LOG_EVENT_ID_SKIP_RESTORE_AT_INSTALL,
+ packageInfo,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- mBMMEventSender.putMonitoringExtra(/*extras=*/null,
+ mBMMEventSender.putMonitoringExtra(
+ /* extras= */ null,
BackupManagerMonitor.EXTRA_LOG_OPERATION_TYPE,
BackupAnnotations.OperationType.RESTORE));
}
@@ -3576,10 +3580,12 @@ public class UserBackupManagerService {
}
// Tell the PackageManager to proceed with the post-install handling for this package.
- Slog.d(TAG, addUserIdToLogMessage(mUserId, "Finishing install immediately"));
+ Slog.d(TAG, mLogIdMsg + "Finishing install immediately");
try {
mPackageManagerBinder.finishPackageInstall(token, false);
- } catch (RemoteException e) { /* can't happen */ }
+ } catch (RemoteException e) {
+ /* can't happen */
+ }
}
}
@@ -3592,8 +3598,9 @@ public class UserBackupManagerService {
/** Hand off a restore session. */
public IRestoreSession beginRestoreSession(String packageName, String transport) {
- Slog.d(TAG, addUserIdToLogMessage(mUserId,
- "beginRestoreSession: pkg=" + packageName + " transport=" + transport));
+ Slog.d(
+ TAG,
+ mLogIdMsg + "beginRestoreSession: pkg=" + packageName + " transport=" + transport);
boolean needPermission = true;
if (transport == null) {
@@ -3604,10 +3611,7 @@ public class UserBackupManagerService {
try {
app = mPackageManager.getPackageInfoAsUser(packageName, 0, mUserId);
} catch (NameNotFoundException nnf) {
- Slog.w(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Asked to restore nonexistent pkg " + packageName));
+ Slog.w(TAG, mLogIdMsg + "Asked to restore nonexistent pkg " + packageName);
throw new IllegalArgumentException("Package " + packageName + " not found");
}
@@ -3624,46 +3628,45 @@ public class UserBackupManagerService {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BACKUP, "beginRestoreSession");
} else {
- Slog.d(TAG, addUserIdToLogMessage(mUserId,
- "restoring self on current transport; no permission needed"));
+ Slog.d(TAG, mLogIdMsg + "restoring self on current transport; no permission needed");
}
int backupDestination;
TransportConnection transportConnection = null;
try {
- transportConnection = mTransportManager.getTransportClientOrThrow(
- transport, /* caller */"BMS.beginRestoreSession");
+ transportConnection =
+ mTransportManager.getTransportClientOrThrow(
+ transport, /* caller */ "BMS.beginRestoreSession");
backupDestination = getBackupDestinationFromTransport(transportConnection);
- } catch (TransportNotAvailableException | TransportNotRegisteredException
+ } catch (TransportNotAvailableException
+ | TransportNotRegisteredException
| RemoteException e) {
Slog.w(TAG, "Failed to get operation type from transport: " + e);
return null;
} finally {
if (transportConnection != null) {
- mTransportManager.disposeOfTransportClient(transportConnection,
- /* caller */"BMS.beginRestoreSession");
+ mTransportManager.disposeOfTransportClient(
+ transportConnection, /* caller */ "BMS.beginRestoreSession");
}
}
synchronized (this) {
if (mActiveRestoreSession != null) {
- Slog.i(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Restore session requested but one already active"));
+ Slog.i(TAG, mLogIdMsg + "Restore session requested but one already active");
return null;
}
if (mBackupRunning) {
- Slog.i(
- TAG,
- addUserIdToLogMessage(
- mUserId,
- "Restore session requested but currently running backups"));
+ Slog.i(TAG, mLogIdMsg + "Restore session requested but currently running backups");
return null;
}
- mActiveRestoreSession = new ActiveRestoreSession(this, packageName, transport,
- getEligibilityRulesForOperation(backupDestination));
- mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT,
+ mActiveRestoreSession =
+ new ActiveRestoreSession(
+ this,
+ packageName,
+ transport,
+ getEligibilityRulesForOperation(backupDestination));
+ mBackupHandler.sendEmptyMessageDelayed(
+ MSG_RESTORE_SESSION_TIMEOUT,
mAgentTimeoutParameters.getRestoreSessionTimeoutMillis());
}
return mActiveRestoreSession;
@@ -3673,10 +3676,9 @@ public class UserBackupManagerService {
public void clearRestoreSession(ActiveRestoreSession currentSession) {
synchronized (this) {
if (currentSession != mActiveRestoreSession) {
- Slog.e(TAG, addUserIdToLogMessage(mUserId, "ending non-current restore session"));
+ Slog.e(TAG, mLogIdMsg + "ending non-current restore session");
} else {
- Slog.d(TAG, addUserIdToLogMessage(mUserId,
- "Clearing restore session and halting timeout"));
+ Slog.d(TAG, mLogIdMsg + "Clearing restore session and halting timeout");
mActiveRestoreSession = null;
mBackupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
}
@@ -3688,11 +3690,14 @@ public class UserBackupManagerService {
* outstanding asynchronous backup/restore operation.
*/
public void opComplete(int token, long result) {
- mOperationStorage.onOperationComplete(token, result, callback -> {
- Pair<BackupRestoreTask, Long> callbackAndResult = Pair.create(callback, result);
- Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, callbackAndResult);
- mBackupHandler.sendMessage(msg);
- });
+ mOperationStorage.onOperationComplete(
+ token,
+ result,
+ callback -> {
+ Pair<BackupRestoreTask, Long> callbackAndResult = Pair.create(callback, result);
+ Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, callbackAndResult);
+ mBackupHandler.sendMessage(msg);
+ });
}
/** Checks if the package is eligible for backup. */
@@ -3748,10 +3753,16 @@ public class UserBackupManagerService {
return getEligibilityRules(mPackageManager, mUserId, mContext, backupDestination);
}
- private static BackupEligibilityRules getEligibilityRules(PackageManager packageManager,
- int userId, Context context, @BackupDestination int backupDestination) {
- return new BackupEligibilityRules(packageManager,
- LocalServices.getService(PackageManagerInternal.class), userId, context,
+ private static BackupEligibilityRules getEligibilityRules(
+ PackageManager packageManager,
+ int userId,
+ Context context,
+ @BackupDestination int backupDestination) {
+ return new BackupEligibilityRules(
+ packageManager,
+ LocalServices.getService(PackageManagerInternal.class),
+ userId,
+ context,
backupDestination);
}
@@ -3793,20 +3804,20 @@ public class UserBackupManagerService {
}
private void dumpBMMEvents(PrintWriter pw) {
- BackupManagerMonitorDumpsysUtils bm =
- new BackupManagerMonitorDumpsysUtils();
+ BackupManagerMonitorDumpsysUtils bm = new BackupManagerMonitorDumpsysUtils();
if (bm.deleteExpiredBMMEvents()) {
pw.println("BACKUP MANAGER MONITOR EVENTS HAVE EXPIRED");
return;
}
File events = bm.getBMMEventsFile();
- if (events.length() == 0){
+ if (events.length() == 0) {
// We have not recorded BMMEvents yet.
pw.println("NO BACKUP MANAGER MONITOR EVENTS");
return;
- } else if (bm.isFileLargerThanSizeLimit(events)){
- pw.println("BACKUP MANAGER MONITOR EVENTS FILE OVER SIZE LIMIT - "
- + "future events will not be recorded");
+ } else if (bm.isFileLargerThanSizeLimit(events)) {
+ pw.println(
+ "BACKUP MANAGER MONITOR EVENTS FILE OVER SIZE LIMIT - "
+ + "future events will not be recorded");
}
pw.println("START OF BACKUP MANAGER MONITOR EVENTS");
try (BufferedReader reader = new BufferedReader(new FileReader(events))) {
@@ -3826,16 +3837,27 @@ public class UserBackupManagerService {
// Add prefix for only non-system users so that system user dumpsys is the same as before
String userPrefix = mUserId == UserHandle.USER_SYSTEM ? "" : "User " + mUserId + ":";
synchronized (mQueueLock) {
- pw.println(userPrefix + "Backup Manager is " + (mEnabled ? "enabled" : "disabled")
- + " / " + (!mSetupComplete ? "not " : "") + "setup complete / "
- + (this.mPendingInits.size() == 0 ? "not " : "") + "pending init");
+ pw.println(
+ userPrefix
+ + "Backup Manager is "
+ + (mEnabled ? "enabled" : "disabled")
+ + " / "
+ + (!mSetupComplete ? "not " : "")
+ + "setup complete / "
+ + (this.mPendingInits.size() == 0 ? "not " : "")
+ + "pending init");
pw.println("Auto-restore is " + (mAutoRestore ? "enabled" : "disabled"));
if (mBackupRunning) pw.println("Backup currently running");
pw.println(isBackupOperationInProgress() ? "Backup in progress" : "No backups running");
- pw.println("Framework scheduling is "
- + (isFrameworkSchedulingEnabled() ? "enabled" : "disabled"));
- pw.println("Last backup pass started: " + mLastBackupPass
- + " (now = " + System.currentTimeMillis() + ')');
+ pw.println(
+ "Framework scheduling is "
+ + (isFrameworkSchedulingEnabled() ? "enabled" : "disabled"));
+ pw.println(
+ "Last backup pass started: "
+ + mLastBackupPass
+ + " (now = "
+ + System.currentTimeMillis()
+ + ')');
pw.println(" next scheduled: " + KeyValueBackupJob.nextScheduled(mUserId));
pw.println(userPrefix + "Transport whitelist:");
@@ -3848,21 +3870,27 @@ public class UserBackupManagerService {
final String[] transports = listAllTransports();
if (transports != null) {
for (String t : transports) {
- pw.println((t.equals(mTransportManager.getCurrentTransportName()) ? " * "
- : " ") + t);
+ pw.println(
+ (t.equals(mTransportManager.getCurrentTransportName())
+ ? " * "
+ : " ")
+ + t);
try {
- File dir = new File(mBaseStateDir,
- mTransportManager.getTransportDirName(t));
- pw.println(" destination: "
- + mTransportManager.getTransportCurrentDestinationString(t));
- pw.println(" intent: "
- + mTransportManager.getTransportConfigurationIntent(t));
+ File dir =
+ new File(mBaseStateDir, mTransportManager.getTransportDirName(t));
+ pw.println(
+ " destination: "
+ + mTransportManager.getTransportCurrentDestinationString(
+ t));
+ pw.println(
+ " intent: "
+ + mTransportManager.getTransportConfigurationIntent(t));
for (File f : dir.listFiles()) {
pw.println(
" " + f.getName() + " - " + f.length() + " state bytes");
}
} catch (Exception e) {
- Slog.e(TAG, addUserIdToLogMessage(mUserId, "Error in transport"), e);
+ Slog.e(TAG, mLogIdMsg + "Error in transport", e);
pw.println(" Error: " + e);
}
}
@@ -3892,8 +3920,10 @@ public class UserBackupManagerService {
}
}
- pw.println(userPrefix + "Ancestral packages: "
- + (mAncestralPackages == null ? "none" : mAncestralPackages.size()));
+ pw.println(
+ userPrefix
+ + "Ancestral packages: "
+ + (mAncestralPackages == null ? "none" : mAncestralPackages.size()));
if (mAncestralPackages != null) {
for (String pkg : mAncestralPackages) {
pw.println(" " + pkg);
@@ -3919,29 +3949,35 @@ public class UserBackupManagerService {
pw.println(entry.packageName);
}
pw.println(userPrefix + "Agent timeouts:");
- pw.println(" KvBackupAgentTimeoutMillis: "
- + mAgentTimeoutParameters.getKvBackupAgentTimeoutMillis());
- pw.println(" FullBackupAgentTimeoutMillis: "
- + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis());
- pw.println(" SharedBackupAgentTimeoutMillis: "
- + mAgentTimeoutParameters.getSharedBackupAgentTimeoutMillis());
- pw.println(" RestoreAgentTimeoutMillis (system): "
- + mAgentTimeoutParameters.getRestoreAgentTimeoutMillis(
- Process.FIRST_APPLICATION_UID - 1));
- pw.println(" RestoreAgentTimeoutMillis: "
- + mAgentTimeoutParameters.getRestoreAgentTimeoutMillis(
- Process.FIRST_APPLICATION_UID));
- pw.println(" RestoreAgentFinishedTimeoutMillis: "
- + mAgentTimeoutParameters.getRestoreAgentFinishedTimeoutMillis());
- pw.println(" QuotaExceededTimeoutMillis: "
- + mAgentTimeoutParameters.getQuotaExceededTimeoutMillis());
-
+ pw.println(
+ " KvBackupAgentTimeoutMillis: "
+ + mAgentTimeoutParameters.getKvBackupAgentTimeoutMillis());
+ pw.println(
+ " FullBackupAgentTimeoutMillis: "
+ + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis());
+ pw.println(
+ " SharedBackupAgentTimeoutMillis: "
+ + mAgentTimeoutParameters.getSharedBackupAgentTimeoutMillis());
+ pw.println(
+ " RestoreAgentTimeoutMillis (system): "
+ + mAgentTimeoutParameters.getRestoreAgentTimeoutMillis(
+ Process.FIRST_APPLICATION_UID - 1));
+ pw.println(
+ " RestoreAgentTimeoutMillis: "
+ + mAgentTimeoutParameters.getRestoreAgentTimeoutMillis(
+ Process.FIRST_APPLICATION_UID));
+ pw.println(
+ " RestoreAgentFinishedTimeoutMillis: "
+ + mAgentTimeoutParameters.getRestoreAgentFinishedTimeoutMillis());
+ pw.println(
+ " QuotaExceededTimeoutMillis: "
+ + mAgentTimeoutParameters.getQuotaExceededTimeoutMillis());
}
}
@VisibleForTesting
- @BackupDestination int getBackupDestinationFromTransport(
- TransportConnection transportConnection)
+ @BackupDestination
+ int getBackupDestinationFromTransport(TransportConnection transportConnection)
throws TransportNotAvailableException, RemoteException {
if (!shouldUseNewBackupEligibilityRules()) {
// Return the default to stick to the legacy behaviour.
@@ -3950,8 +3986,9 @@ public class UserBackupManagerService {
final long oldCallingId = Binder.clearCallingIdentity();
try {
- BackupTransportClient transport = transportConnection.connectOrThrow(
- /* caller */ "BMS.getBackupDestinationFromTransport");
+ BackupTransportClient transport =
+ transportConnection.connectOrThrow(
+ /* caller */ "BMS.getBackupDestinationFromTransport");
if ((transport.getTransportFlags() & BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER) != 0) {
return BackupDestination.DEVICE_TRANSFER;
} else {
@@ -3964,15 +4001,10 @@ public class UserBackupManagerService {
@VisibleForTesting
boolean shouldUseNewBackupEligibilityRules() {
- return FeatureFlagUtils.isEnabled(mContext,
- FeatureFlagUtils.SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES);
+ return FeatureFlagUtils.isEnabled(
+ mContext, FeatureFlagUtils.SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES);
}
- private static String addUserIdToLogMessage(int userId, String message) {
- return "[UserID:" + userId + "] " + message;
- }
-
-
public IBackupManager getBackupManagerBinder() {
return mBackupManagerBinder;
}
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 260ea75a1f4c..f401e6b66093 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -21,7 +21,6 @@ import static android.Manifest.permission.ADD_TRUSTED_DISPLAY;
import static android.app.admin.DevicePolicyManager.NEARBY_STREAMING_ENABLED;
import static android.app.admin.DevicePolicyManager.NEARBY_STREAMING_NOT_CONTROLLED_BY_POLICY;
import static android.app.admin.DevicePolicyManager.NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY;
-import static android.companion.virtual.VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED;
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
import static android.companion.virtual.VirtualDeviceParams.NAVIGATION_POLICY_DEFAULT_ALLOWED;
@@ -483,26 +482,13 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
}
mVirtualDeviceLog.logCreated(deviceId, mOwnerUid);
- if (Flags.vdmPublicApis()) {
- mPublicVirtualDeviceObject = new VirtualDevice(
- this, getDeviceId(), getPersistentDeviceId(), mParams.getName(),
- getDisplayName());
- } else {
- mPublicVirtualDeviceObject = new VirtualDevice(
- this, getDeviceId(), getPersistentDeviceId(), mParams.getName());
- }
+ mPublicVirtualDeviceObject = new VirtualDevice(
+ this, getDeviceId(), getPersistentDeviceId(), mParams.getName(), getDisplayName());
- if (Flags.dynamicPolicy()) {
- mActivityPolicyExemptions = new ArraySet<>(
- mParams.getDevicePolicy(POLICY_TYPE_ACTIVITY) == DEVICE_POLICY_DEFAULT
- ? mParams.getBlockedActivities()
- : mParams.getAllowedActivities());
- } else {
- mActivityPolicyExemptions =
- mParams.getDefaultActivityPolicy() == ACTIVITY_POLICY_DEFAULT_ALLOWED
- ? mParams.getBlockedActivities()
- : mParams.getAllowedActivities();
- }
+ mActivityPolicyExemptions = new ArraySet<>(
+ mParams.getDevicePolicy(POLICY_TYPE_ACTIVITY) == DEVICE_POLICY_DEFAULT
+ ? mParams.getBlockedActivities()
+ : mParams.getAllowedActivities());
if (Flags.vdmCustomIme() && mParams.getInputMethodComponent() != null) {
final String imeId = mParams.getInputMethodComponent().flattenToShortString();
@@ -587,12 +573,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
@Override // Binder call
public @VirtualDeviceParams.DevicePolicy int getDevicePolicy(
@VirtualDeviceParams.PolicyType int policyType) {
- if (Flags.dynamicPolicy()) {
- synchronized (mVirtualDeviceLock) {
- return mDevicePolicies.get(policyType, DEVICE_POLICY_DEFAULT);
- }
- } else {
- return mParams.getDevicePolicy(policyType);
+ synchronized (mVirtualDeviceLock) {
+ return mDevicePolicies.get(policyType, DEVICE_POLICY_DEFAULT);
}
}
@@ -891,9 +873,6 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
public void setDevicePolicy(@VirtualDeviceParams.DynamicPolicyType int policyType,
@VirtualDeviceParams.DevicePolicy int devicePolicy) {
checkCallerIsDeviceOwner();
- if (!Flags.dynamicPolicy()) {
- return;
- }
switch (policyType) {
case POLICY_TYPE_RECENTS:
@@ -924,23 +903,21 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
}
break;
case POLICY_TYPE_CLIPBOARD:
- if (Flags.crossDeviceClipboard()) {
- if (devicePolicy == DEVICE_POLICY_CUSTOM
+ if (devicePolicy == DEVICE_POLICY_CUSTOM
&& mContext.checkCallingOrSelfPermission(ADD_TRUSTED_DISPLAY)
!= PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
- + "set a custom clipboard policy.");
- }
- synchronized (mVirtualDeviceLock) {
- for (int i = 0; i < mVirtualDisplays.size(); i++) {
- VirtualDisplayWrapper wrapper = mVirtualDisplays.valueAt(i);
- if (!wrapper.isTrusted() && !wrapper.isMirror()) {
- throw new SecurityException("All displays must be trusted for "
- + "devices with custom clipboard policy.");
- }
+ throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
+ + "set a custom clipboard policy.");
+ }
+ synchronized (mVirtualDeviceLock) {
+ for (int i = 0; i < mVirtualDisplays.size(); i++) {
+ VirtualDisplayWrapper wrapper = mVirtualDisplays.valueAt(i);
+ if (!wrapper.isTrusted() && !wrapper.isMirror()) {
+ throw new SecurityException("All displays must be trusted for "
+ + "devices with custom clipboard policy.");
}
- mDevicePolicies.put(policyType, devicePolicy);
}
+ mDevicePolicies.put(policyType, devicePolicy);
}
break;
case POLICY_TYPE_BLOCKED_ACTIVITY:
@@ -1374,10 +1351,6 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
}
private boolean hasCustomAudioInputSupportInternal() {
- if (!Flags.vdmPublicApis()) {
- return false;
- }
-
if (!android.media.audiopolicy.Flags.audioMixTestApi()) {
return false;
}
@@ -1443,15 +1416,11 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
private GenericWindowPolicyController createWindowPolicyControllerLocked(
@NonNull Set<String> displayCategories) {
final boolean activityLaunchAllowedByDefault =
- Flags.dynamicPolicy()
- ? getDevicePolicy(POLICY_TYPE_ACTIVITY) == DEVICE_POLICY_DEFAULT
- : mParams.getDefaultActivityPolicy() == ACTIVITY_POLICY_DEFAULT_ALLOWED;
+ getDevicePolicy(POLICY_TYPE_ACTIVITY) == DEVICE_POLICY_DEFAULT;
final boolean crossTaskNavigationAllowedByDefault =
mParams.getDefaultNavigationPolicy() == NAVIGATION_POLICY_DEFAULT_ALLOWED;
final boolean showTasksInHostDeviceRecents =
getDevicePolicy(POLICY_TYPE_RECENTS) == DEVICE_POLICY_DEFAULT;
- final ComponentName homeComponent =
- Flags.vdmCustomHome() ? mParams.getHomeComponent() : null;
if (mActivityListenerAdapter == null) {
mActivityListenerAdapter = new GwpcActivityListener();
@@ -1472,7 +1441,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
mActivityListenerAdapter,
displayCategories,
showTasksInHostDeviceRecents,
- homeComponent);
+ mParams.getHomeComponent());
gwpc.registerRunningAppsChangedListener(/* listener= */ this);
return gwpc;
}
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 40726b4331e2..0b335d318d64 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -216,17 +216,14 @@ public class VirtualDeviceManagerService extends SystemService {
VIRTUAL_DEVICE_SERVICE_ORDERED_ID,
mActivityInterceptorCallback);
- if (Flags.persistentDeviceIdApi()) {
- CompanionDeviceManager cdm =
- getContext().getSystemService(CompanionDeviceManager.class);
- if (cdm != null) {
- onCdmAssociationsChanged(cdm.getAllAssociations(UserHandle.USER_ALL));
- cdm.addOnAssociationsChangedListener(getContext().getMainExecutor(),
- this::onCdmAssociationsChanged, UserHandle.USER_ALL);
- } else {
- Slog.e(TAG, "Failed to find CompanionDeviceManager. No CDM association info "
- + " will be available.");
- }
+ CompanionDeviceManager cdm = getContext().getSystemService(CompanionDeviceManager.class);
+ if (cdm != null) {
+ onCdmAssociationsChanged(cdm.getAllAssociations(UserHandle.USER_ALL));
+ cdm.addOnAssociationsChangedListener(getContext().getMainExecutor(),
+ this::onCdmAssociationsChanged, UserHandle.USER_ALL);
+ } else {
+ Slog.e(TAG, "Failed to find CompanionDeviceManager. No CDM association info "
+ + " will be available.");
}
if (android.companion.virtualdevice.flags.Flags.deviceAwareDisplayPower()) {
mStrongAuthTracker = new StrongAuthTracker(getContext());
@@ -321,16 +318,14 @@ public class VirtualDeviceManagerService extends SystemService {
mVirtualDevices.remove(deviceId);
}
- if (Flags.vdmPublicApis()) {
- mVirtualDeviceListeners.broadcast(listener -> {
- try {
- listener.onVirtualDeviceClosed(deviceId);
- } catch (RemoteException e) {
- Slog.i(TAG, "Failed to invoke onVirtualDeviceClosed listener: "
- + e.getMessage());
- }
- });
- }
+ mVirtualDeviceListeners.broadcast(listener -> {
+ try {
+ listener.onVirtualDeviceClosed(deviceId);
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Failed to invoke onVirtualDeviceClosed listener: "
+ + e.getMessage());
+ }
+ });
Intent i = new Intent(VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED);
i.putExtra(VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID, deviceId);
@@ -338,14 +333,6 @@ public class VirtualDeviceManagerService extends SystemService {
final long identity = Binder.clearCallingIdentity();
try {
getContext().sendBroadcastAsUser(i, UserHandle.ALL);
-
- if (!Flags.persistentDeviceIdApi()) {
- synchronized (mVirtualDeviceManagerLock) {
- if (mVirtualDevices.size() == 0) {
- unregisterCdmAssociationListener();
- }
- }
- }
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -379,21 +366,6 @@ public class VirtualDeviceManagerService extends SystemService {
}
}
- @RequiresPermission(android.Manifest.permission.MANAGE_COMPANION_DEVICES)
- private void registerCdmAssociationListener() {
- final CompanionDeviceManager cdm = getContext().getSystemService(
- CompanionDeviceManager.class);
- cdm.addOnAssociationsChangedListener(getContext().getMainExecutor(),
- mCdmAssociationListener);
- }
-
- @RequiresPermission(android.Manifest.permission.MANAGE_COMPANION_DEVICES)
- private void unregisterCdmAssociationListener() {
- final CompanionDeviceManager cdm = getContext().getSystemService(
- CompanionDeviceManager.class);
- cdm.removeOnAssociationsChangedListener(mCdmAssociationListener);
- }
-
void onCdmAssociationsChanged(List<AssociationInfo> associations) {
ArrayMap<String, AssociationInfo> vdmAssociations = new ArrayMap<>();
for (int i = 0; i < associations.size(); ++i) {
@@ -479,9 +451,8 @@ public class VirtualDeviceManagerService extends SystemService {
AssociationInfo associationInfo = getAssociationInfo(packageName, associationId);
if (associationInfo == null) {
throw new IllegalArgumentException("No association with ID " + associationId);
- } else if (!VIRTUAL_DEVICE_COMPANION_DEVICE_PROFILES
- .contains(associationInfo.getDeviceProfile())
- && Flags.persistentDeviceIdApi()) {
+ } else if (!VIRTUAL_DEVICE_COMPANION_DEVICE_PROFILES.contains(
+ associationInfo.getDeviceProfile())) {
throw new IllegalArgumentException("Unsupported CDM Association device profile "
+ associationInfo.getDeviceProfile() + " for virtual device creation.");
}
@@ -522,27 +493,17 @@ public class VirtualDeviceManagerService extends SystemService {
Counter.logIncrement("virtual_devices.value_virtual_devices_created_count");
synchronized (mVirtualDeviceManagerLock) {
- if (!Flags.persistentDeviceIdApi() && mVirtualDevices.size() == 0) {
- final long callingId = Binder.clearCallingIdentity();
- try {
- registerCdmAssociationListener();
- } finally {
- Binder.restoreCallingIdentity(callingId);
- }
- }
mVirtualDevices.put(deviceId, virtualDevice);
}
- if (Flags.vdmPublicApis()) {
- mVirtualDeviceListeners.broadcast(listener -> {
- try {
- listener.onVirtualDeviceCreated(deviceId);
- } catch (RemoteException e) {
- Slog.i(TAG, "Failed to invoke onVirtualDeviceCreated listener: "
- + e.getMessage());
- }
- });
- }
+ mVirtualDeviceListeners.broadcast(listener -> {
+ try {
+ listener.onVirtualDeviceCreated(deviceId);
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Failed to invoke onVirtualDeviceCreated listener: "
+ + e.getMessage());
+ }
+ });
Counter.logIncrementWithUid(
"virtual_devices.value_virtual_devices_created_with_uid_count",
attributionSource.getUid());
diff --git a/services/core/Android.bp b/services/core/Android.bp
index d6bffcb7d21d..42385fc5bdb0 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -37,6 +37,7 @@ filegroup {
":framework_native_aidl",
":gsiservice_aidl",
":installd_aidl",
+ ":mmd_aidl",
":storaged_aidl",
":vold_aidl",
],
@@ -246,6 +247,7 @@ java_library_static {
"aconfig_new_storage_flags_lib",
"powerstats_flags_lib",
"locksettings_flags_lib",
+ "mmd_flags_lib",
"profiling_flags_lib",
"android.adpf.sessionmanager_aidl-java",
"uprobestats_flags_java_lib",
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 6459016eec75..87222a60d82d 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -564,7 +564,8 @@ public class GestureLauncherService extends SystemService {
return Settings.Secure.getIntForUser(
context.getContentResolver(),
Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE,
- LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER,
+ context.getResources().getInteger(
+ R.integer.config_doubleTapPowerGestureMultiTargetDefaultAction),
userId);
}
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index 6858e2941ff9..ef769cf6217c 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -9,6 +9,7 @@ per-file DisplayThread.java = michaelwr@google.com, ogunwale@google.com
# Zram writeback
per-file ZramWriteback.java = minchan@google.com, rajekumar@google.com
+per-file ZramMaintenance.java = kawasin@google.com
# ServiceWatcher
per-file ServiceWatcher.java = sooniln@google.com
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index b7bc4e4827ef..19e7e062758a 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -41,6 +41,7 @@ import static android.os.storage.OnObbStateChangeListener.ERROR_NOT_MOUNTED;
import static android.os.storage.OnObbStateChangeListener.ERROR_PERMISSION_DENIED;
import static android.os.storage.OnObbStateChangeListener.MOUNTED;
import static android.os.storage.OnObbStateChangeListener.UNMOUNTED;
+import static android.mmd.flags.Flags.mmdEnabled;
import static com.android.internal.util.XmlUtils.readStringAttribute;
import static com.android.internal.util.XmlUtils.writeStringAttribute;
@@ -945,12 +946,17 @@ class StorageManagerService extends IStorageManager.Stub
});
refreshZramSettings();
- // Schedule zram writeback unless zram is disabled by persist.sys.zram_enabled
- String zramPropValue = SystemProperties.get(ZRAM_ENABLED_PROPERTY);
- if (!zramPropValue.equals("0")
- && mContext.getResources().getBoolean(
+ if (mmdEnabled()) {
+ // TODO: b/375432472 - Start zram maintenance only when zram is enabled.
+ ZramMaintenance.startZramMaintenance(mContext);
+ } else {
+ // Schedule zram writeback unless zram is disabled by persist.sys.zram_enabled
+ String zramPropValue = SystemProperties.get(ZRAM_ENABLED_PROPERTY);
+ if (!zramPropValue.equals("0")
+ && mContext.getResources().getBoolean(
com.android.internal.R.bool.config_zramWriteback)) {
- ZramWriteback.scheduleZramWriteback(mContext);
+ ZramWriteback.scheduleZramWriteback(mContext);
+ }
}
configureTranscoding();
@@ -977,7 +983,7 @@ class StorageManagerService extends IStorageManager.Stub
// sole writer.
SystemProperties.set(ZRAM_ENABLED_PROPERTY, desiredPropertyValue);
// Schedule writeback only if zram is being enabled.
- if (desiredPropertyValue.equals("1")
+ if (!mmdEnabled() && desiredPropertyValue.equals("1")
&& mContext.getResources().getBoolean(
com.android.internal.R.bool.config_zramWriteback)) {
ZramWriteback.scheduleZramWriteback(mContext);
diff --git a/services/core/java/com/android/server/ZramMaintenance.java b/services/core/java/com/android/server/ZramMaintenance.java
new file mode 100644
index 000000000000..cdb48122e321
--- /dev/null
+++ b/services/core/java/com/android/server/ZramMaintenance.java
@@ -0,0 +1,118 @@
+/*
+ * 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;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.IMmd;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.util.Slog;
+
+import java.time.Duration;
+
+/**
+ * Schedules zram maintenance (e.g. zram writeback, zram recompression).
+ *
+ * <p>ZramMaintenance notifies mmd the good timing to execute zram maintenance based on:
+ *
+ * <ul>
+ * <li>Enough interval has passed.
+ * <li>The system is idle.
+ * <li>The battery is not low.
+ * </ul>
+ */
+public class ZramMaintenance extends JobService {
+ private static final String TAG = ZramMaintenance.class.getName();
+ // Job id must be unique across all clients of the same uid. ZramMaintenance uses the bug number
+ // as the job id.
+ private static final int JOB_ID = 375432472;
+ private static final ComponentName sZramMaintenance =
+ new ComponentName("android", ZramMaintenance.class.getName());
+
+ private static final String FIRST_DELAY_SECONDS_PROP =
+ "mm.zram.maintenance.first_delay_seconds";
+ // The default is 1 hour.
+ private static final long DEFAULT_FIRST_DELAY_SECONDS = 3600;
+ private static final String PERIODIC_DELAY_SECONDS_PROP =
+ "mm.zram.maintenance.periodic_delay_seconds";
+ // The default is 1 hour.
+ private static final long DEFAULT_PERIODIC_DELAY_SECONDS = 3600;
+ private static final String REQUIRE_DEVICE_IDLE_PROP =
+ "mm.zram.maintenance.require_device_idle";
+ private static final boolean DEFAULT_REQUIRE_DEVICE_IDLE =
+ true;
+ private static final String REQUIRE_BATTERY_NOT_LOW_PROP =
+ "mm.zram.maintenance.require_battry_not_low";
+ private static final boolean DEFAULT_REQUIRE_BATTERY_NOT_LOW =
+ true;
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ IBinder binder = ServiceManager.getService("mmd");
+ if (binder != null) {
+ IMmd mmd = IMmd.Stub.asInterface(binder);
+ try {
+ mmd.doZramMaintenance();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to doZramMaintenance", e);
+ }
+ } else {
+ Slog.w(TAG, "binder not found");
+ }
+ Duration delay = Duration.ofSeconds(SystemProperties.getLong(PERIODIC_DELAY_SECONDS_PROP,
+ DEFAULT_PERIODIC_DELAY_SECONDS));
+ scheduleZramMaintenance(this, delay);
+ return true;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ return false;
+ }
+
+ /**
+ * Starts periodical zram maintenance.
+ */
+ public static void startZramMaintenance(Context context) {
+ Duration delay = Duration.ofSeconds(
+ SystemProperties.getLong(FIRST_DELAY_SECONDS_PROP, DEFAULT_FIRST_DELAY_SECONDS));
+ scheduleZramMaintenance(context, delay);
+ }
+
+ private static void scheduleZramMaintenance(Context context, Duration delay) {
+ JobScheduler js = context.getSystemService(JobScheduler.class);
+
+ if (js != null) {
+ js.schedule(new JobInfo.Builder(JOB_ID, sZramMaintenance)
+ .setMinimumLatency(delay.toMillis())
+ .setRequiresDeviceIdle(
+ SystemProperties.getBoolean(REQUIRE_DEVICE_IDLE_PROP,
+ DEFAULT_REQUIRE_DEVICE_IDLE))
+ .setRequiresBatteryNotLow(
+ SystemProperties.getBoolean(REQUIRE_BATTERY_NOT_LOW_PROP,
+ DEFAULT_REQUIRE_BATTERY_NOT_LOW))
+ .build());
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 4b8770b3cd35..50876dafa819 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -277,7 +277,9 @@ final class ActivityManagerConstants extends ContentObserver {
private static final long DEFAULT_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION = 1000L;
/** The default value to {@link #KEY_FREEZER_CUTOFF_ADJ} */
- private static final int DEFAULT_FREEZER_CUTOFF_ADJ = ProcessList.CACHED_APP_MIN_ADJ;
+ private static final int DEFAULT_FREEZER_CUTOFF_ADJ =
+ Flags.prototypeAggressiveFreezing() ? ProcessList.HOME_APP_ADJ
+ : ProcessList.CACHED_APP_MIN_ADJ;
/**
* Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 600aa1fdaa04..644077a7e6bb 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -528,6 +528,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub
public void systemServicesReady() {
mStats.saveBatteryUsageStatsOnReset(mBatteryUsageStatsProvider, mPowerStatsStore,
isBatteryUsageStatsAccumulationSupported());
+ mStats.resetBatteryHistoryOnNewSession(
+ !Flags.extendedBatteryHistoryContinuousCollectionEnabled());
MultiStatePowerAttributor attributor = (MultiStatePowerAttributor) mPowerAttributor;
mStats.setPowerStatsCollectorEnabled(BatteryConsumer.POWER_COMPONENT_CPU,
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index c99e8c8ff799..d3a52543f321 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -155,6 +155,7 @@ public class SettingsToPropertiesMapper {
"android_core_networking",
"android_health_services",
"android_sdk",
+ "android_kernel",
"aoc",
"app_widgets",
"arc_next",
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index cfcede8ee40d..d9be47193c89 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -270,6 +270,16 @@ flag {
}
flag {
+ name: "prototype_aggressive_freezing"
+ namespace: "backstage_power"
+ description: "Grant PROCESS_CAPABILITY_CPU_TIME to as many valid states and aggressively freeze other states"
+ bug: "370798593"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "add_modify_raw_oom_adj_service_level"
namespace: "backstage_power"
description: "Add a SERVICE_ADJ level to the modifyRawOomAdj method"
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 8a63f9a24ea3..d2073aaa834c 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -2589,7 +2589,6 @@ public class AppOpsService extends IAppOpsService.Stub {
Map<String, Ops> packages = uidState.pkgOps;
Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
- boolean uidChanged = false;
while (it.hasNext()) {
Map.Entry<String, Ops> ent = it.next();
String packageName = ent.getKey();
@@ -2622,7 +2621,6 @@ public class AppOpsService extends IAppOpsService.Stub {
newMode,
UserHandle.getUserId(curOp.uid));
changed = true;
- uidChanged = true;
final int uid = curOp.uidState.uid;
callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
previousMode, mOpModeWatchers.get(curOp.op));
diff --git a/services/core/java/com/android/server/appop/DiscreteOpsDbHelper.java b/services/core/java/com/android/server/appop/DiscreteOpsDbHelper.java
index e4c36cc214e8..695032e6476c 100644
--- a/services/core/java/com/android/server/appop/DiscreteOpsDbHelper.java
+++ b/services/core/java/com/android/server/appop/DiscreteOpsDbHelper.java
@@ -110,7 +110,12 @@ class DiscreteOpsDbHelper extends SQLiteOpenHelper {
}
db.setTransactionSuccessful();
} finally {
- db.endTransaction();
+ try {
+ db.endTransaction();
+ } catch (SQLiteException exception) {
+ Slog.e(LOG_TAG, "Couldn't commit transaction when inserting discrete ops, database"
+ + " file size (bytes) : " + getDatabaseFile().length(), exception);
+ }
}
}
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 78f71877afed..6122fdaafe77 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -17,8 +17,6 @@
package com.android.server.clipboard;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
-import static android.companion.virtual.VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED;
-import static android.companion.virtual.VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID;
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CLIPBOARD;
import static android.content.Context.DEVICE_ID_DEFAULT;
@@ -46,7 +44,6 @@ import android.content.Context;
import android.content.IClipboard;
import android.content.IOnPrimaryClipChangedListener;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
@@ -219,35 +216,7 @@ public class ClipboardService extends SystemService {
@Override
public void onStart() {
publishBinderService(Context.CLIPBOARD_SERVICE, new ClipboardImpl());
- if (!android.companion.virtual.flags.Flags.vdmPublicApis() && mVdmInternal != null) {
- registerVirtualDeviceBroadcastReceiver();
- } else if (android.companion.virtual.flags.Flags.vdmPublicApis() && mVdm != null) {
- registerVirtualDeviceListener();
- }
- }
-
- private void registerVirtualDeviceBroadcastReceiver() {
- if (mVirtualDeviceRemovedReceiver != null) {
- return;
- }
- mVirtualDeviceRemovedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (!intent.getAction().equals(ACTION_VIRTUAL_DEVICE_REMOVED)) {
- return;
- }
- final int removedDeviceId =
- intent.getIntExtra(EXTRA_VIRTUAL_DEVICE_ID, DEVICE_ID_INVALID);
- synchronized (mLock) {
- for (int i = mClipboards.numMaps() - 1; i >= 0; i--) {
- mClipboards.delete(mClipboards.keyAt(i), removedDeviceId);
- }
- }
- }
- };
- IntentFilter filter = new IntentFilter(ACTION_VIRTUAL_DEVICE_REMOVED);
- getContext().registerReceiver(mVirtualDeviceRemovedReceiver, filter,
- Context.RECEIVER_NOT_EXPORTED);
+ registerVirtualDeviceListener();
}
private void registerVirtualDeviceListener() {
diff --git a/services/core/java/com/android/server/crashrecovery/OWNERS b/services/core/java/com/android/server/crashrecovery/OWNERS
index daa02111f71f..02df9860030d 100644
--- a/services/core/java/com/android/server/crashrecovery/OWNERS
+++ b/services/core/java/com/android/server/crashrecovery/OWNERS
@@ -1,3 +1,2 @@
-ancr@google.com
harshitmahajan@google.com
robertogil@google.com
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 93d9b8d30a2e..25a2f60b85b2 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -643,8 +643,9 @@ final class ColorFade {
.setSecure(isSecure)
.setBLASTLayer();
mBLASTSurfaceControl = b.build();
- mBLASTBufferQueue = new BLASTBufferQueue("ColorFade", mBLASTSurfaceControl,
- mDisplayWidth, mDisplayHeight, PixelFormat.TRANSLUCENT);
+ mBLASTBufferQueue = new BLASTBufferQueue("ColorFade", /*updateDestinationFrame*/ true);
+ mBLASTBufferQueue.update(mBLASTSurfaceControl, mDisplayWidth, mDisplayHeight,
+ PixelFormat.TRANSLUCENT);
mSurface = mBLASTBufferQueue.createSurface();
}
return true;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index b530da2a5f5e..ca001b9c7e6d 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -4188,6 +4188,9 @@ public final class DisplayManagerService extends SystemService {
}
}
+ /**
+ * This method must not be called with mCallback held or deadlock will ensue.
+ */
@Override
public void binderDied() {
synchronized (mCallback) {
@@ -4248,17 +4251,8 @@ public final class DisplayManagerService extends SystemService {
}
}
- return transmitDisplayEvent(displayId, event);
- }
-
- /**
- * Transmit a single display event. The client is presumed ready. Return true on success
- * and false if the client died.
- */
- private boolean transmitDisplayEvent(int displayId, @DisplayEvent int event) {
- // The client is ready to receive the event.
try {
- mCallback.onDisplayEvent(displayId, event);
+ transmitDisplayEvent(displayId, event);
return true;
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to notify process "
@@ -4269,6 +4263,18 @@ public final class DisplayManagerService extends SystemService {
}
/**
+ * Transmit a single display event. The client is presumed ready. This throws if the
+ * client has died; callers must catch and handle the exception. The exception cannot be
+ * handled directly here because {@link #binderDied()} must not be called whilst holding
+ * the mCallback lock.
+ */
+ private void transmitDisplayEvent(int displayId, @DisplayEvent int event)
+ throws RemoteException {
+ // The client is ready to receive the event.
+ mCallback.onDisplayEvent(displayId, event);
+ }
+
+ /**
* Return true if the client is interested in this event.
*/
private boolean shouldSendDisplayEvent(@DisplayEvent int event) {
@@ -4376,27 +4382,32 @@ public final class DisplayManagerService extends SystemService {
// would be unusual to do so. The method returns true on success.
// This is only used if {@link deferDisplayEventsWhenFrozen()} is true.
public boolean dispatchPending() {
- synchronized (mCallback) {
- if (mPendingEvents == null || mPendingEvents.isEmpty() || !mAlive) {
- return true;
- }
- if (!isReadyLocked()) {
- return false;
- }
- for (int i = 0; i < mPendingEvents.size(); i++) {
- Event displayEvent = mPendingEvents.get(i);
- if (DEBUG) {
- Slog.d(TAG, "Send pending display event #" + i + " "
- + displayEvent.displayId + "/"
- + displayEvent.event + " to " + mUid + "/" + mPid);
+ try {
+ synchronized (mCallback) {
+ if (mPendingEvents == null || mPendingEvents.isEmpty() || !mAlive) {
+ return true;
+ }
+ if (!isReadyLocked()) {
+ return false;
}
- if (!transmitDisplayEvent(displayEvent.displayId, displayEvent.event)) {
- Slog.d(TAG, "Drop pending events for dead process " + mPid);
- break;
+ for (int i = 0; i < mPendingEvents.size(); i++) {
+ Event displayEvent = mPendingEvents.get(i);
+ if (DEBUG) {
+ Slog.d(TAG, "Send pending display event #" + i + " "
+ + displayEvent.displayId + "/"
+ + displayEvent.event + " to " + mUid + "/" + mPid);
+ }
+ transmitDisplayEvent(displayEvent.displayId, displayEvent.event);
}
+ mPendingEvents.clear();
+ return true;
}
- mPendingEvents.clear();
- return true;
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to notify process "
+ + mPid + " that display topology changed, assuming it died.", ex);
+ binderDied();
+ return false;
+
}
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index d37dd3018fde..b49c01b3e2a8 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -83,6 +83,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private static final String PROPERTY_EMULATOR_CIRCULAR = "ro.boot.emulator.circular";
+ private static final double DEFAULT_DISPLAY_SIZE = 24.0;
+
private final LongSparseArray<LocalDisplayDevice> mDevices = new LongSparseArray<>();
private final Injector mInjector;
@@ -526,6 +528,21 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private int getLogicalDensity() {
DensityMapping densityMapping = getDisplayDeviceConfig().getDensityMapping();
if (densityMapping == null) {
+ if (getFeatureFlags().isBaseDensityForExternalDisplaysEnabled()
+ && !mStaticDisplayInfo.isInternal) {
+ double dpi;
+
+ if (mActiveSfDisplayMode.xDpi > 0 && mActiveSfDisplayMode.yDpi > 0) {
+ dpi = Math.sqrt((Math.pow(mActiveSfDisplayMode.xDpi, 2)
+ + Math.pow(mActiveSfDisplayMode.yDpi, 2)) / 2);
+ } else {
+ // xDPI and yDPI is missing, calculate DPI from display resolution and
+ // default display size
+ dpi = Math.sqrt(Math.pow(mInfo.width, 2) + Math.pow(mInfo.height, 2))
+ / DEFAULT_DISPLAY_SIZE;
+ }
+ return (int) (dpi + 0.5);
+ }
return (int) (mStaticDisplayInfo.density * 160 + 0.5);
}
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 4e57d6791ff6..43aa6f46da78 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -258,6 +258,11 @@ public class DisplayManagerFlags {
Flags::subscribeGranularDisplayEvents
);
+ private final FlagState mBaseDensityForExternalDisplays = new FlagState(
+ Flags.FLAG_BASE_DENSITY_FOR_EXTERNAL_DISPLAYS,
+ Flags::baseDensityForExternalDisplays
+ );
+
/**
* @return {@code true} if 'port' is allowed in display layout configuration file.
*/
@@ -553,6 +558,14 @@ public class DisplayManagerFlags {
}
/**
+ * @return {@code true} if the flag for base density for external displays is enabled
+ */
+ public boolean isBaseDensityForExternalDisplaysEnabled() {
+ return mBaseDensityForExternalDisplays.isEnabled();
+ }
+
+
+ /**
* dumps all flagstates
* @param pw printWriter
*/
@@ -606,6 +619,7 @@ public class DisplayManagerFlags {
pw.println(" " + mDisplayListenerPerformanceImprovementsFlagState);
pw.println(" " + mSubscribeGranularDisplayEvents);
pw.println(" " + mEnableDisplayContentModeManagementFlagState);
+ pw.println(" " + mBaseDensityForExternalDisplays);
}
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 afae07c88f8d..00a9dcb71b4b 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
@@ -471,3 +471,11 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "base_density_for_external_displays"
+ namespace: "lse_desktop_experience"
+ description: "Feature flag for setting a base density for external displays."
+ bug: "382954433"
+ is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 0c04be10d06d..67b1ec305d7f 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -20,6 +20,7 @@ import static android.Manifest.permission.BIND_DREAM_SERVICE;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.service.dreams.Flags.allowDreamWhenPostured;
import static android.service.dreams.Flags.cleanupDreamSettingsOnUninstall;
import static android.service.dreams.Flags.dreamHandlesBeingObscured;
@@ -110,12 +111,13 @@ public final class DreamManagerService extends SystemService {
/** Constants for the when to activate dreams. */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({DREAM_ON_DOCK, DREAM_ON_CHARGE, DREAM_ON_DOCK_OR_CHARGE})
+ @IntDef({DREAM_DISABLED, DREAM_ON_DOCK, DREAM_ON_CHARGE, DREAM_ON_POSTURED})
public @interface WhenToDream {}
- private static final int DREAM_DISABLED = 0x0;
- private static final int DREAM_ON_DOCK = 0x1;
- private static final int DREAM_ON_CHARGE = 0x2;
- private static final int DREAM_ON_DOCK_OR_CHARGE = 0x3;
+
+ private static final int DREAM_DISABLED = 0;
+ private static final int DREAM_ON_DOCK = 1 << 0;
+ private static final int DREAM_ON_CHARGE = 1 << 1;
+ private static final int DREAM_ON_POSTURED = 1 << 2;
private final Object mLock = new Object();
@@ -137,6 +139,7 @@ public final class DreamManagerService extends SystemService {
private final boolean mDreamsEnabledByDefaultConfig;
private final boolean mDreamsActivatedOnChargeByDefault;
private final boolean mDreamsActivatedOnDockByDefault;
+ private final boolean mDreamsActivatedOnPosturedByDefault;
private final boolean mKeepDreamingWhenUnpluggingDefault;
private final boolean mDreamsDisabledByAmbientModeSuppressionConfig;
@@ -152,6 +155,7 @@ public final class DreamManagerService extends SystemService {
@WhenToDream private int mWhenToDream;
private boolean mIsDocked;
private boolean mIsCharging;
+ private boolean mIsPostured;
// A temporary dream component that, when present, takes precedence over user configured dream
// component.
@@ -270,6 +274,8 @@ public final class DreamManagerService extends SystemService {
com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
mDreamsActivatedOnDockByDefault = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
+ mDreamsActivatedOnPosturedByDefault = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_dreamsActivatedOnPosturedByDefault);
mSettingsObserver = new SettingsObserver(mHandler);
mKeepDreamingWhenUnpluggingDefault = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_keepDreamingWhenUnplugging);
@@ -328,6 +334,9 @@ public final class DreamManagerService extends SystemService {
Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK),
false, mSettingsObserver, UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED),
+ false, mSettingsObserver, UserHandle.USER_ALL);
+ mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SCREENSAVER_ENABLED),
false, mSettingsObserver, UserHandle.USER_ALL);
@@ -392,6 +401,8 @@ public final class DreamManagerService extends SystemService {
pw.println("mDreamsEnabledSetting=" + mDreamsEnabledSetting);
pw.println("mDreamsActivatedOnDockByDefault=" + mDreamsActivatedOnDockByDefault);
pw.println("mDreamsActivatedOnChargeByDefault=" + mDreamsActivatedOnChargeByDefault);
+ pw.println("mDreamsActivatedOnPosturedByDefault="
+ + mDreamsActivatedOnPosturedByDefault);
pw.println("mIsDocked=" + mIsDocked);
pw.println("mIsCharging=" + mIsCharging);
pw.println("mWhenToDream=" + mWhenToDream);
@@ -409,15 +420,28 @@ public final class DreamManagerService extends SystemService {
synchronized (mLock) {
final ContentResolver resolver = mContext.getContentResolver();
- final int activateWhenCharging = (Settings.Secure.getIntForUser(resolver,
+ mWhenToDream = DREAM_DISABLED;
+
+ if ((Settings.Secure.getIntForUser(resolver,
Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
mDreamsActivatedOnChargeByDefault ? 1 : 0,
- UserHandle.USER_CURRENT) != 0) ? DREAM_ON_CHARGE : DREAM_DISABLED;
- final int activateWhenDocked = (Settings.Secure.getIntForUser(resolver,
+ UserHandle.USER_CURRENT) != 0)) {
+ mWhenToDream |= DREAM_ON_CHARGE;
+ }
+
+ if (Settings.Secure.getIntForUser(resolver,
Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
mDreamsActivatedOnDockByDefault ? 1 : 0,
- UserHandle.USER_CURRENT) != 0) ? DREAM_ON_DOCK : DREAM_DISABLED;
- mWhenToDream = activateWhenCharging + activateWhenDocked;
+ UserHandle.USER_CURRENT) != 0) {
+ mWhenToDream |= DREAM_ON_DOCK;
+ }
+
+ if (Settings.Secure.getIntForUser(resolver,
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED,
+ mDreamsActivatedOnPosturedByDefault ? 1 : 0,
+ UserHandle.USER_CURRENT) != 0) {
+ mWhenToDream |= DREAM_ON_POSTURED;
+ }
mDreamsEnabledSetting = (Settings.Secure.getIntForUser(resolver,
Settings.Secure.SCREENSAVER_ENABLED,
@@ -508,6 +532,10 @@ public final class DreamManagerService extends SystemService {
return mIsDocked;
}
+ if ((mWhenToDream & DREAM_ON_POSTURED) == DREAM_ON_POSTURED) {
+ return mIsPostured;
+ }
+
return false;
}
}
@@ -646,6 +674,14 @@ public final class DreamManagerService extends SystemService {
}
}
+ private void setDevicePosturedInternal(boolean isPostured) {
+ Slog.d(TAG, "Device postured: " + isPostured);
+ synchronized (mLock) {
+ mIsPostured = isPostured;
+ mHandler.post(() -> mPowerManagerInternal.setDevicePostured(isPostured));
+ }
+ }
+
/**
* If doze is true, returns the doze component for the user.
* Otherwise, returns the system dream component, if present.
@@ -1294,6 +1330,22 @@ public final class DreamManagerService extends SystemService {
}
}
+ @Override
+ public void setDevicePostured(boolean isPostured) {
+ if (!allowDreamWhenPostured()) {
+ return;
+ }
+
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ setDevicePosturedInternal(isPostured);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
boolean canLaunchDreamActivity(String dreamPackageName, String packageName,
int callingUid) {
if (dreamPackageName == null || packageName == null) {
diff --git a/services/core/java/com/android/server/hdmi/PowerStatusMonitorActionFromPlayback.java b/services/core/java/com/android/server/hdmi/PowerStatusMonitorActionFromPlayback.java
index d05ded5367d0..a2465d1c3a5d 100644
--- a/services/core/java/com/android/server/hdmi/PowerStatusMonitorActionFromPlayback.java
+++ b/services/core/java/com/android/server/hdmi/PowerStatusMonitorActionFromPlayback.java
@@ -28,21 +28,17 @@ import com.android.internal.annotations.VisibleForTesting;
*/
public class PowerStatusMonitorActionFromPlayback extends HdmiCecFeatureAction {
private static final String TAG = "PowerStatusMonitorActionFromPlayback";
+ // State that waits for next monitoring.
+ private static final int STATE_WAIT_FOR_NEXT_MONITORING = 1;
// State that waits for <Report Power Status> once sending <Give Device Power Status>
- // to all external devices.
- private static final int STATE_WAIT_FOR_REPORT_POWER_STATUS = 1;
- // State that waits for next monitoring.
- private static final int STATE_WAIT_FOR_NEXT_MONITORING = 2;
+ // to the TV.
+ private static final int STATE_WAIT_FOR_REPORT_POWER_STATUS = 2;
+
// Monitoring interval (60s)
@VisibleForTesting
protected static final int MONITORING_INTERVAL_MS = 60000;
// Timeout once sending <Give Device Power Status>
- private static final int REPORT_POWER_STATUS_TIMEOUT_MS = 5000;
- // Maximum number of retries in case the <Give Device Power Status> failed being sent or times
- // out.
- private static final int GIVE_POWER_STATUS_FOR_SOURCE_RETRIES = 5;
- private int mPowerStatusRetries = 0;
PowerStatusMonitorActionFromPlayback(HdmiCecLocalDevice source) {
super(source);
@@ -68,11 +64,10 @@ public class PowerStatusMonitorActionFromPlayback extends HdmiCecFeatureAction {
private boolean handleReportPowerStatusFromTv(HdmiCecMessage cmd) {
int powerStatus = cmd.getParams()[0] & 0xFF;
- mState = STATE_WAIT_FOR_NEXT_MONITORING;
- addTimer(mState, MONITORING_INTERVAL_MS);
if (powerStatus == POWER_STATUS_STANDBY) {
Slog.d(TAG, "TV reported it turned off, going to sleep.");
source().getService().standby();
+ finish();
return true;
}
return false;
@@ -80,34 +75,28 @@ public class PowerStatusMonitorActionFromPlayback extends HdmiCecFeatureAction {
@Override
void handleTimerEvent(int state) {
+ if (mState != state) {
+ return;
+ }
+
switch (mState) {
case STATE_WAIT_FOR_NEXT_MONITORING:
- mPowerStatusRetries = 0;
queryPowerStatus();
break;
case STATE_WAIT_FOR_REPORT_POWER_STATUS:
- handleTimeout();
+ mState = STATE_WAIT_FOR_NEXT_MONITORING;
+ addTimer(mState, MONITORING_INTERVAL_MS);
+ break;
+ default:
break;
}
}
private void queryPowerStatus() {
sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(),
- Constants.ADDR_TV));
+ Constants.ADDR_TV));
mState = STATE_WAIT_FOR_REPORT_POWER_STATUS;
- addTimer(mState, REPORT_POWER_STATUS_TIMEOUT_MS);
- }
-
- private void handleTimeout() {
- if (mState == STATE_WAIT_FOR_REPORT_POWER_STATUS) {
- if (mPowerStatusRetries++ < GIVE_POWER_STATUS_FOR_SOURCE_RETRIES) {
- queryPowerStatus();
- } else {
- mPowerStatusRetries = 0;
- mState = STATE_WAIT_FOR_NEXT_MONITORING;
- addTimer(mState, MONITORING_INTERVAL_MS);
- }
- }
+ addTimer(mState, HdmiConfig.TIMEOUT_MS);
}
}
diff --git a/services/core/java/com/android/server/input/InputGestureManager.java b/services/core/java/com/android/server/input/InputGestureManager.java
index 93fdbc787ed0..fd755e3cefe2 100644
--- a/services/core/java/com/android/server/input/InputGestureManager.java
+++ b/services/core/java/com/android/server/input/InputGestureManager.java
@@ -87,7 +87,20 @@ final class InputGestureManager {
createKeyTrigger(KeyEvent.KEYCODE_V, KeyEvent.META_CTRL_ON),
createKeyTrigger(KeyEvent.KEYCODE_X, KeyEvent.META_CTRL_ON),
createKeyTrigger(KeyEvent.KEYCODE_Z, KeyEvent.META_CTRL_ON),
- createKeyTrigger(KeyEvent.KEYCODE_Y, KeyEvent.META_CTRL_ON)
+ createKeyTrigger(KeyEvent.KEYCODE_Y, KeyEvent.META_CTRL_ON),
+ // Used for magnification viewport control.
+ createKeyTrigger(KeyEvent.KEYCODE_MINUS,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON),
+ createKeyTrigger(KeyEvent.KEYCODE_EQUALS,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON),
+ createKeyTrigger(KeyEvent.KEYCODE_DPAD_LEFT,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON),
+ createKeyTrigger(KeyEvent.KEYCODE_DPAD_RIGHT,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON),
+ createKeyTrigger(KeyEvent.KEYCODE_DPAD_UP,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON),
+ createKeyTrigger(KeyEvent.KEYCODE_DPAD_DOWN,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON)
));
public InputGestureManager(Context context) {
@@ -216,24 +229,6 @@ final class InputGestureManager {
systemShortcuts.add(createKeyGesture(KeyEvent.KEYCODE_T,
KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK));
- systemShortcuts.add(createKeyGesture(KeyEvent.KEYCODE_MINUS,
- KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_ZOOM_OUT));
- systemShortcuts.add(createKeyGesture(KeyEvent.KEYCODE_EQUALS,
- KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_ZOOM_IN));
- systemShortcuts.add(createKeyGesture(KeyEvent.KEYCODE_DPAD_LEFT,
- KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_PAN_LEFT));
- systemShortcuts.add(createKeyGesture(KeyEvent.KEYCODE_DPAD_RIGHT,
- KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_PAN_RIGHT));
- systemShortcuts.add(createKeyGesture(KeyEvent.KEYCODE_DPAD_UP,
- KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_PAN_UP));
- systemShortcuts.add(createKeyGesture(KeyEvent.KEYCODE_DPAD_DOWN,
- KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_PAN_DOWN));
systemShortcuts.add(createKeyGesture(KeyEvent.KEYCODE_M,
KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION));
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
index 281db0ae9518..5fe8318dbb3f 100644
--- a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
+++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
@@ -40,6 +40,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.os.Binder;
import android.os.IBinder;
@@ -58,6 +59,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import java.io.PrintWriter;
@@ -78,6 +80,7 @@ public final class ImeVisibilityStateComputer {
private final int mUserId;
private final InputMethodManagerService mService;
+ private final UserManagerInternal mUserManagerInternal;
private final WindowManagerInternal mWindowManagerInternal;
final InputMethodManagerService.ImeDisplayValidator mImeDisplayValidator;
@@ -188,6 +191,7 @@ public final class ImeVisibilityStateComputer {
public ImeVisibilityStateComputer(@NonNull InputMethodManagerService service,
@UserIdInt int userId) {
this(service,
+ LocalServices.getService(UserManagerInternal.class),
LocalServices.getService(WindowManagerInternal.class),
LocalServices.getService(WindowManagerInternal.class)::getDisplayImePolicy,
new ImeVisibilityPolicy(), userId);
@@ -196,12 +200,15 @@ public final class ImeVisibilityStateComputer {
@VisibleForTesting
public ImeVisibilityStateComputer(@NonNull InputMethodManagerService service,
@NonNull Injector injector) {
- this(service, injector.getWmService(), injector.getImeValidator(),
- new ImeVisibilityPolicy(), injector.getUserId());
+ this(service, injector.getUserManagerService(), injector.getWmService(),
+ injector.getImeValidator(), new ImeVisibilityPolicy(), injector.getUserId());
}
interface Injector {
@NonNull
+ UserManagerInternal getUserManagerService();
+
+ @NonNull
WindowManagerInternal getWmService();
@NonNull
@@ -212,11 +219,13 @@ public final class ImeVisibilityStateComputer {
}
private ImeVisibilityStateComputer(InputMethodManagerService service,
+ UserManagerInternal userManagerInternal,
WindowManagerInternal wmService,
InputMethodManagerService.ImeDisplayValidator imeDisplayValidator,
ImeVisibilityPolicy imePolicy, @UserIdInt int userId) {
mUserId = userId;
mService = service;
+ mUserManagerInternal = userManagerInternal;
mWindowManagerInternal = wmService;
mImeDisplayValidator = imeDisplayValidator;
mPolicy = imePolicy;
@@ -337,7 +346,16 @@ public final class ImeVisibilityStateComputer {
@GuardedBy("ImfLock.class")
int computeImeDisplayId(@NonNull ImeTargetWindowState state, int displayId) {
- final int displayToShowIme = computeImeDisplayIdForTarget(displayId, mImeDisplayValidator);
+ final int displayToShowIme;
+ final PackageManager pm = mService.mContext.getPackageManager();
+ if (pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+ && mUserManagerInternal.isVisibleBackgroundFullUser(mUserId)
+ && Flags.fallbackDisplayForSecondaryUserOnSecondaryDisplay()) {
+ displayToShowIme = mService.computeImeDisplayIdForVisibleBackgroundUserOnAutomotive(
+ displayId, mUserId, mImeDisplayValidator);
+ } else {
+ displayToShowIme = computeImeDisplayIdForTarget(displayId, mImeDisplayValidator);
+ }
state.setImeDisplayId(displayToShowIme);
final boolean imeHiddenByPolicy = displayToShowIme == INVALID_DISPLAY;
mPolicy.setImeHiddenByDisplayPolicy(imeHiddenByPolicy);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 1f414ac07ba3..45c7cffd462b 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2345,8 +2345,32 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
* {@link WindowManager#DISPLAY_IME_POLICY_HIDE}
*/
static int computeImeDisplayIdForTarget(int displayId, @NonNull ImeDisplayValidator checker) {
- if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) {
- return FALLBACK_DISPLAY_ID;
+ return computeImeDisplayIdForTargetInner(displayId, checker, FALLBACK_DISPLAY_ID);
+ }
+
+ /**
+ * Find the display where the IME should be shown for a visible background user.
+ *
+ * @param displayId the ID of the display where the IME client target is
+ * @param userId the ID of the user who own the IME
+ * @param checker instance of {@link ImeDisplayValidator} which is used for
+ * checking display config to adjust the final target display
+ * @return the ID of the display where the IME should be shown or
+ * {@link android.view.Display#INVALID_DISPLAY} if the display has an ImePolicy of
+ * {@link WindowManager#DISPLAY_IME_POLICY_HIDE}
+ */
+ int computeImeDisplayIdForVisibleBackgroundUserOnAutomotive(
+ int displayId, @UserIdInt int userId, @NonNull ImeDisplayValidator checker) {
+ // Visible background user can be assigned to a secondary display, not the default display.
+ // The main display assigned to the user will be used as the fallback display.
+ final int mainDisplayId = mUserManagerInternal.getMainDisplayAssignedToUser(userId);
+ return computeImeDisplayIdForTargetInner(displayId, checker, mainDisplayId);
+ }
+
+ private static int computeImeDisplayIdForTargetInner(
+ int displayId, @NonNull ImeDisplayValidator checker, int fallbackDisplayId) {
+ if (displayId == fallbackDisplayId || displayId == INVALID_DISPLAY) {
+ return fallbackDisplayId;
}
// Show IME window on fallback display when the display doesn't support system decorations
@@ -2356,9 +2380,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
return displayId;
} else if (result == DISPLAY_IME_POLICY_HIDE) {
return INVALID_DISPLAY;
- } else {
- return FALLBACK_DISPLAY_ID;
}
+ return fallbackDisplayId;
}
@GuardedBy("ImfLock.class")
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
index a41194b898ac..1949d103a0d6 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
@@ -499,9 +499,11 @@ import java.util.List;
/* package */
static HubMessage createHubMessage(Message message) {
boolean isReliable = (message.flags & Message.FLAG_REQUIRES_DELIVERY_STATUS) != 0;
- return new HubMessage.Builder(message.type, message.content)
+ HubMessage outMessage = new HubMessage.Builder(message.type, message.content)
.setResponseRequired(isReliable)
.build();
+ outMessage.setMessageSequenceNumber(message.sequenceNumber);
+ return outMessage;
}
/**
diff --git a/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java b/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java
index 6e650c207358..bf54fd720d42 100644
--- a/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java
+++ b/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java
@@ -30,6 +30,7 @@ import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@@ -271,9 +272,10 @@ class HubInfoRegistry implements ContextHubHalEndpointCallback.IEndpointLifecycl
void unregisterEndpointDiscoveryCallback(IContextHubEndpointDiscoveryCallback callback) {
Objects.requireNonNull(callback, "callback cannot be null");
synchronized (mCallbackLock) {
- for (DiscoveryCallback discoveryCallback : mEndpointDiscoveryCallbacks) {
- if (discoveryCallback.getCallback().asBinder() == callback.asBinder()) {
- mEndpointDiscoveryCallbacks.remove(discoveryCallback);
+ Iterator<DiscoveryCallback> iterator = mEndpointDiscoveryCallbacks.iterator();
+ while (iterator.hasNext()) {
+ if (iterator.next().getCallback().asBinder() == callback.asBinder()) {
+ iterator.remove();
break;
}
}
@@ -303,7 +305,9 @@ class HubInfoRegistry implements ContextHubHalEndpointCallback.IEndpointLifecycl
HubEndpointInfo[] endpointInfos,
BiConsumer<IContextHubEndpointDiscoveryCallback, HubEndpointInfo[]> consumer) {
synchronized (mCallbackLock) {
- for (DiscoveryCallback discoveryCallback : mEndpointDiscoveryCallbacks) {
+ Iterator<DiscoveryCallback> iterator = mEndpointDiscoveryCallbacks.iterator();
+ while (iterator.hasNext()) {
+ DiscoveryCallback discoveryCallback = iterator.next();
ArrayList<HubEndpointInfo> infoList = new ArrayList<>();
for (HubEndpointInfo endpointInfo : endpointInfos) {
if (discoveryCallback.isMatch(endpointInfo)) {
diff --git a/services/core/java/com/android/server/location/fudger/LocationFudger.java b/services/core/java/com/android/server/location/fudger/LocationFudger.java
index 28e21b71dcc9..39ee0cbeacce 100644
--- a/services/core/java/com/android/server/location/fudger/LocationFudger.java
+++ b/services/core/java/com/android/server/location/fudger/LocationFudger.java
@@ -68,6 +68,17 @@ public class LocationFudger {
private static final double MAX_LATITUDE =
90.0 - (1.0 / APPROXIMATE_METERS_PER_DEGREE_AT_EQUATOR);
+ // The average edge length in km of an S2 cell, indexed by S2 levels 0 to
+ // 13. Level 13 is the highest level used for coarsening.
+ // This approximation assumes the S2 cells are squares.
+ // For density-based coarsening, we use the edge to set the accuracy of the
+ // coarsened location.
+ // The values are from http://s2geometry.io/resources/s2cell_statistics.html
+ // We take square root of the average area.
+ private static final float[] S2_CELL_AVG_EDGE_PER_LEVEL = new float[] {
+ 9220.14f, 4610.07f, 2305.04f, 1152.52f, 576.26f, 288.13f, 144.06f,
+ 72.03f, 36.02f, 20.79f, 9f, 5.05f, 2.25f, 1.13f, 0.57f};
+
private final float mAccuracyM;
private final Clock mClock;
private final Random mRandom;
@@ -194,12 +205,14 @@ public class LocationFudger {
// The new algorithm is applied if and only if (1) the flag is on, (2) the cache has been
// set, and (3) the cache has successfully queried the provider for the default coarsening
// value.
+ float accuracy = mAccuracyM;
if (Flags.populationDensityProvider() && Flags.densityBasedCoarseLocations()
&& cacheCopy != null) {
if (cacheCopy.hasDefaultValue()) {
// New algorithm that snaps to the center of a S2 cell.
int level = cacheCopy.getCoarseningLevel(latitude, longitude);
coarsened = snapToCenterOfS2Cell(latitude, longitude, level);
+ accuracy = getS2CellApproximateEdge(level);
} else {
// Try to fetch the default value. The answer won't come in time, but will be used
// for the next location to coarsen.
@@ -214,7 +227,7 @@ public class LocationFudger {
coarse.setLatitude(coarsened[LAT_INDEX]);
coarse.setLongitude(coarsened[LNG_INDEX]);
- coarse.setAccuracy(Math.max(mAccuracyM, coarse.getAccuracy()));
+ coarse.setAccuracy(Math.max(accuracy, coarse.getAccuracy()));
synchronized (this) {
mCachedFineLocation = fine;
@@ -224,6 +237,19 @@ public class LocationFudger {
return coarse;
}
+ // Returns the average edge length in meters of an S2 cell at the given
+ // level. This is computed as if the S2 cell were a square. We do not need
+ // an exact value, only a rough approximation.
+ @VisibleForTesting
+ protected float getS2CellApproximateEdge(int level) {
+ if (level < 0) {
+ level = 0;
+ } else if (level >= S2_CELL_AVG_EDGE_PER_LEVEL.length) {
+ level = S2_CELL_AVG_EDGE_PER_LEVEL.length - 1;
+ }
+ return S2_CELL_AVG_EDGE_PER_LEVEL[level] * 1000;
+ }
+
// quantize location by snapping to a grid. this is the primary means of obfuscation. it
// gives nice consistent results and is very effective at hiding the true location (as
// long as you are not sitting on a grid boundary, which the random offsets mitigate).
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 0d0cdd83cc73..a0e543300ce7 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -137,6 +137,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.pm.RoSystemFeatures;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
@@ -1325,7 +1326,7 @@ public class LockSettingsService extends ILockSettings.Stub {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN,
"Requires MANAGE_WEAK_ESCROW_TOKEN permission.");
- if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ if (!RoSystemFeatures.hasFeatureAutomotive(mContext)) {
throw new IllegalArgumentException(
"Weak escrow token are only for automotive devices.");
}
@@ -3613,7 +3614,7 @@ public class LockSettingsService extends ILockSettings.Stub {
}
// Escrow tokens are enabled on automotive builds.
- if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ if (RoSystemFeatures.hasFeatureAutomotive(mContext)) {
return;
}
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index d6f7d3bdd4a4..23e9ac5008f7 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -545,6 +545,16 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider {
for (RoutingSessionInfo session : sessions) {
if (session == null) continue;
session = assignProviderIdForSession(session);
+
+ if (Flags.enableMirroringInMediaRouter2()) {
+ var systemSessionCallback =
+ mSystemSessionCallbacks.get(session.getOriginalId());
+ if (systemSessionCallback != null) {
+ systemSessionCallback.onSessionUpdate(session);
+ continue;
+ }
+ }
+
int sourceIndex = findSessionByIdLocked(session);
if (sourceIndex < 0) {
mSessionInfos.add(targetIndex++, session);
diff --git a/services/core/java/com/android/server/media/RemoteDisplayProviderProxy.java b/services/core/java/com/android/server/media/RemoteDisplayProviderProxy.java
index ba98a0a9fd4e..fd1bea9ae639 100644
--- a/services/core/java/com/android/server/media/RemoteDisplayProviderProxy.java
+++ b/services/core/java/com/android/server/media/RemoteDisplayProviderProxy.java
@@ -25,8 +25,9 @@ import android.media.IRemoteDisplayProvider;
import android.media.RemoteDisplayState;
import android.os.Handler;
import android.os.IBinder;
-import android.os.RemoteException;
import android.os.IBinder.DeathRecipient;
+import android.os.Looper;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
@@ -35,10 +36,8 @@ import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.Objects;
-/**
- * Maintains a connection to a particular remote display provider service.
- */
-final class RemoteDisplayProviderProxy implements ServiceConnection {
+/** Maintains a connection to a particular remote display provider service. */
+final class RemoteDisplayProviderProxy {
private static final String TAG = "RemoteDisplayProvider"; // max. 23 chars
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -61,12 +60,15 @@ final class RemoteDisplayProviderProxy implements ServiceConnection {
private RemoteDisplayState mDisplayState;
private boolean mScheduledDisplayStateChangedCallback;
- public RemoteDisplayProviderProxy(Context context, ComponentName componentName,
- int userId) {
+ private final ServiceConnection mServiceConnection =
+ new ServiceConnectionImpl();
+
+ /* package */ RemoteDisplayProviderProxy(
+ Context context, ComponentName componentName, int userId, Looper looper) {
mContext = context;
mComponentName = componentName;
mUserId = userId;
- mHandler = new Handler();
+ mHandler = new Handler(looper);
}
public void dump(PrintWriter pw, String prefix) {
@@ -190,9 +192,12 @@ final class RemoteDisplayProviderProxy implements ServiceConnection {
Intent service = new Intent(RemoteDisplayState.SERVICE_INTERFACE);
service.setComponent(mComponentName);
try {
- mBound = mContext.bindServiceAsUser(service, this,
- Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
- new UserHandle(mUserId));
+ mBound =
+ mContext.bindServiceAsUser(
+ service,
+ mServiceConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+ new UserHandle(mUserId));
if (!mBound && DEBUG) {
Slog.d(TAG, this + ": Bind failed");
}
@@ -212,12 +217,11 @@ final class RemoteDisplayProviderProxy implements ServiceConnection {
mBound = false;
disconnect();
- mContext.unbindService(this);
+ mContext.unbindService(mServiceConnection);
}
}
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
+ private void onServiceConnectedOnHandler(IBinder service) {
if (DEBUG) {
Slog.d(TAG, this + ": Connected");
}
@@ -241,8 +245,7 @@ final class RemoteDisplayProviderProxy implements ServiceConnection {
}
}
- @Override
- public void onServiceDisconnected(ComponentName name) {
+ private void onServiceDisconnectedOnHandler() {
if (DEBUG) {
Slog.d(TAG, this + ": Service disconnected");
}
@@ -322,6 +325,20 @@ final class RemoteDisplayProviderProxy implements ServiceConnection {
void onDisplayStateChanged(RemoteDisplayProviderProxy provider, RemoteDisplayState state);
}
+ // All methods in this class are called on the main thread.
+ private final class ServiceConnectionImpl implements ServiceConnection {
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mHandler.post(() -> onServiceConnectedOnHandler(service));
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mHandler.post(RemoteDisplayProviderProxy.this::onServiceDisconnectedOnHandler);
+ }
+ }
+
private final class Connection implements DeathRecipient {
private final IRemoteDisplayProvider mProvider;
private final ProviderCallback mCallback;
diff --git a/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java b/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java
index 64c451d03caa..cc03c805fef0 100644
--- a/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java
+++ b/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java
@@ -121,9 +121,11 @@ public final class RemoteDisplayProviderWatcher {
int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name);
if (sourceIndex < 0) {
RemoteDisplayProviderProxy provider =
- new RemoteDisplayProviderProxy(mContext,
- new ComponentName(serviceInfo.packageName, serviceInfo.name),
- mUserId);
+ new RemoteDisplayProviderProxy(
+ mContext,
+ new ComponentName(serviceInfo.packageName, serviceInfo.name),
+ mUserId,
+ mHandler.getLooper());
provider.start();
mProviders.add(targetIndex++, provider);
mCallback.addProvider(provider);
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java
index 8931e3a1426e..011659a616d3 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java
@@ -128,8 +128,20 @@ import java.util.stream.Stream;
targetProviderProxyId, existingSession.getProviderId())) {
// The currently selected route and target route both belong to the same
// provider. We tell the provider to handle the transfer.
- targetProviderProxyRecord.requestTransfer(
- existingSession.getOriginalId(), serviceTargetRoute);
+ if (serviceTargetRoute == null) {
+ notifyRequestFailed(
+ requestId, MediaRoute2ProviderService.REASON_ROUTE_NOT_AVAILABLE);
+ } else {
+ targetProviderProxyRecord.mProxy.transferToRoute(
+ requestId,
+ clientUserHandle,
+ clientPackageName,
+ existingSession.getOriginalId(),
+ targetProviderProxyRecord.mNewOriginalIdToSourceOriginalIdMap.get(
+ routeOriginalId),
+ transferReason);
+ }
+ return;
} else {
// The target route is handled by a provider other than the target one. We need
// to release the existing session.
@@ -429,11 +441,6 @@ import java.util.stream.Stream;
}
}
- public void requestTransfer(String sessionId, MediaRoute2Info targetRoute) {
- // TODO: Map the target route to the source route original id.
- throw new UnsupportedOperationException("TODO Implement");
- }
-
public void releaseSession(long requestId, String originalSessionId) {
mProxy.releaseSession(requestId, originalSessionId);
}
@@ -491,18 +498,19 @@ import java.util.stream.Stream;
() -> {
if (mSessionRecord != null) {
mSessionRecord.onSessionUpdate(sessionInfo);
+ } else {
+ SystemMediaSessionRecord systemMediaSessionRecord =
+ new SystemMediaSessionRecord(mProviderId, sessionInfo);
+ RoutingSessionInfo translatedSession;
+ synchronized (mLock) {
+ mSessionRecord = systemMediaSessionRecord;
+ mPackageNameToSessionRecord.put(
+ mClientPackageName, systemMediaSessionRecord);
+ mPendingSessionCreations.remove(mRequestId);
+ translatedSession = systemMediaSessionRecord.mTranslatedSessionInfo;
+ }
+ onSessionOverrideUpdated(translatedSession);
}
- SystemMediaSessionRecord systemMediaSessionRecord =
- new SystemMediaSessionRecord(mProviderId, sessionInfo);
- RoutingSessionInfo translatedSession;
- synchronized (mLock) {
- mSessionRecord = systemMediaSessionRecord;
- mPackageNameToSessionRecord.put(
- mClientPackageName, systemMediaSessionRecord);
- mPendingSessionCreations.remove(mRequestId);
- translatedSession = systemMediaSessionRecord.mTranslatedSessionInfo;
- }
- onSessionOverrideUpdated(translatedSession);
});
}
@@ -546,7 +554,6 @@ import java.util.stream.Stream;
* The same as {@link #mSourceSessionInfo}, except ids are {@link #asSystemRouteId system
* provider ids}.
*/
- @GuardedBy("SystemMediaRoute2Provider2.this.mLock")
@NonNull
private RoutingSessionInfo mTranslatedSessionInfo;
@@ -559,10 +566,10 @@ import java.util.stream.Stream;
@Override
public void onSessionUpdate(@NonNull RoutingSessionInfo sessionInfo) {
- RoutingSessionInfo translatedSessionInfo = mTranslatedSessionInfo;
+ RoutingSessionInfo translatedSessionInfo = asSystemProviderSession(sessionInfo);
synchronized (mLock) {
mSourceSessionInfo = sessionInfo;
- mTranslatedSessionInfo = asSystemProviderSession(sessionInfo);
+ mTranslatedSessionInfo = translatedSessionInfo;
}
onSessionOverrideUpdated(translatedSessionInfo);
}
diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java
index d440d3ab3521..999e0b4551fe 100644
--- a/services/core/java/com/android/server/media/quality/MediaQualityService.java
+++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java
@@ -16,12 +16,21 @@
package com.android.server.media.quality;
+import static android.media.quality.AmbientBacklightEvent.AMBIENT_BACKLIGHT_EVENT_ENABLED;
+import static android.media.quality.AmbientBacklightEvent.AMBIENT_BACKLIGHT_EVENT_DISABLED;
+import static android.media.quality.AmbientBacklightEvent.AMBIENT_BACKLIGHT_EVENT_METADATA_AVAILABLE;
+import static android.media.quality.AmbientBacklightEvent.AMBIENT_BACKLIGHT_EVENT_INTERRUPTED;
+
+import android.annotation.NonNull;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
+import android.hardware.tv.mediaquality.AmbientBacklightColorFormat;
import android.hardware.tv.mediaquality.IMediaQuality;
+import android.media.quality.AmbientBacklightEvent;
+import android.media.quality.AmbientBacklightMetadata;
import android.media.quality.AmbientBacklightSettings;
import android.media.quality.IAmbientBacklightCallback;
import android.media.quality.IMediaQualityManager;
@@ -42,6 +51,7 @@ import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -60,6 +70,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.UUID;
import java.util.stream.Collectors;
@@ -76,13 +87,16 @@ public class MediaQualityService extends SystemService {
private final MediaQualityDbHelper mMediaQualityDbHelper;
private final BiMap<Long, String> mPictureProfileTempIdMap;
private final BiMap<Long, String> mSoundProfileTempIdMap;
+ private IMediaQuality mMediaQuality;
+ private final HalAmbientBacklightCallback mHalAmbientBacklightCallback;
+ private final Map<String, AmbientBacklightCallbackRecord> mCallbackRecords = new HashMap<>();
private final PackageManager mPackageManager;
private final SparseArray<UserState> mUserStates = new SparseArray<>();
- private IMediaQuality mMediaQuality;
public MediaQualityService(Context context) {
super(context);
mContext = context;
+ mHalAmbientBacklightCallback = new HalAmbientBacklightCallback();
mPackageManager = mContext.getPackageManager();
mPictureProfileTempIdMap = new BiMap<>();
mSoundProfileTempIdMap = new BiMap<>();
@@ -97,6 +111,13 @@ public class MediaQualityService extends SystemService {
if (binder != null) {
Slogf.d(TAG, "binder is not null");
mMediaQuality = IMediaQuality.Stub.asInterface(binder);
+ if (mMediaQuality != null) {
+ try {
+ mMediaQuality.setAmbientBacklightCallback(mHalAmbientBacklightCallback);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to set ambient backlight detector callback", e);
+ }
+ }
}
publishBinderService(Context.MEDIA_QUALITY_SERVICE, new BinderService());
@@ -110,7 +131,7 @@ public class MediaQualityService extends SystemService {
if ((pp.getPackageName() != null && !pp.getPackageName().isEmpty()
&& !incomingPackageEqualsCallingUidPackage(pp.getPackageName()))
&& !hasGlobalPictureQualityServicePermission()) {
- notifyError(null, PictureProfile.ERROR_NO_PERMISSION,
+ notifyOnPictureProfileError(null, PictureProfile.ERROR_NO_PERMISSION,
Binder.getCallingUid(), Binder.getCallingPid());
}
@@ -128,7 +149,9 @@ public class MediaQualityService extends SystemService {
Long id = db.insert(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
null, values);
populateTempIdMap(mPictureProfileTempIdMap, id);
- pp.setProfileId(mPictureProfileTempIdMap.getValue(id));
+ String value = mPictureProfileTempIdMap.getValue(id);
+ pp.setProfileId(value);
+ notifyOnPictureProfileAdded(value, pp, Binder.getCallingUid(), Binder.getCallingPid());
return pp;
}
@@ -136,7 +159,7 @@ public class MediaQualityService extends SystemService {
public void updatePictureProfile(String id, PictureProfile pp, UserHandle user) {
Long dbId = mPictureProfileTempIdMap.getKey(id);
if (!hasPermissionToUpdatePictureProfile(dbId, pp)) {
- notifyError(id, PictureProfile.ERROR_NO_PERMISSION,
+ notifyOnPictureProfileError(id, PictureProfile.ERROR_NO_PERMISSION,
Binder.getCallingUid(), Binder.getCallingPid());
}
@@ -150,6 +173,8 @@ public class MediaQualityService extends SystemService {
SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
db.replace(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
null, values);
+ notifyOnPictureProfileUpdated(mPictureProfileTempIdMap.getValue(dbId),
+ getPictureProfile(dbId), Binder.getCallingUid(), Binder.getCallingPid());
}
private boolean hasPermissionToUpdatePictureProfile(Long dbId, PictureProfile toUpdate) {
@@ -164,8 +189,9 @@ public class MediaQualityService extends SystemService {
public void removePictureProfile(String id, UserHandle user) {
Long dbId = mPictureProfileTempIdMap.getKey(id);
- if (!hasPermissionToRemovePictureProfile(dbId)) {
- notifyError(id, PictureProfile.ERROR_NO_PERMISSION,
+ PictureProfile toDelete = getPictureProfile(dbId);
+ if (!hasPermissionToRemovePictureProfile(toDelete)) {
+ notifyOnPictureProfileError(id, PictureProfile.ERROR_NO_PERMISSION,
Binder.getCallingUid(), Binder.getCallingPid());
}
@@ -176,16 +202,20 @@ public class MediaQualityService extends SystemService {
int result = db.delete(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, selection,
selectionArgs);
if (result == 0) {
- notifyError(id, PictureProfile.ERROR_INVALID_ARGUMENT,
+ notifyOnPictureProfileError(id, PictureProfile.ERROR_INVALID_ARGUMENT,
Binder.getCallingUid(), Binder.getCallingPid());
}
+ notifyOnPictureProfileRemoved(mPictureProfileTempIdMap.getValue(dbId), toDelete,
+ Binder.getCallingUid(), Binder.getCallingPid());
mPictureProfileTempIdMap.remove(dbId);
}
}
- private boolean hasPermissionToRemovePictureProfile(Long dbId) {
- PictureProfile fromDb = getPictureProfile(dbId);
- return fromDb.getName().equalsIgnoreCase(getPackageOfCallingUid());
+ private boolean hasPermissionToRemovePictureProfile(PictureProfile toDelete) {
+ if (toDelete != null) {
+ return toDelete.getName().equalsIgnoreCase(getPackageOfCallingUid());
+ }
+ return false;
}
@Override
@@ -246,7 +276,7 @@ public class MediaQualityService extends SystemService {
public List<PictureProfile> getPictureProfilesByPackage(
String packageName, Bundle options, UserHandle user) {
if (!hasGlobalPictureQualityServicePermission()) {
- notifyError(null, PictureProfile.ERROR_NO_PERMISSION,
+ notifyOnPictureProfileError(null, PictureProfile.ERROR_NO_PERMISSION,
Binder.getCallingUid(), Binder.getCallingPid());
}
@@ -259,8 +289,7 @@ public class MediaQualityService extends SystemService {
}
@Override
- public List<PictureProfile> getAvailablePictureProfiles(
- Bundle options, UserHandle user) {
+ public List<PictureProfile> getAvailablePictureProfiles(Bundle options, UserHandle user) {
String packageName = getPackageOfCallingUid();
if (packageName != null) {
return getPictureProfilesByPackage(packageName, options, user);
@@ -271,7 +300,7 @@ public class MediaQualityService extends SystemService {
@Override
public boolean setDefaultPictureProfile(String profileId, UserHandle user) {
if (!hasGlobalPictureQualityServicePermission()) {
- notifyError(profileId, PictureProfile.ERROR_NO_PERMISSION,
+ notifyOnPictureProfileError(profileId, PictureProfile.ERROR_NO_PERMISSION,
Binder.getCallingUid(), Binder.getCallingPid());
}
// TODO: pass the profile ID to MediaQuality HAL when ready.
@@ -281,7 +310,7 @@ public class MediaQualityService extends SystemService {
@Override
public List<String> getPictureProfilePackageNames(UserHandle user) {
if (!hasGlobalPictureQualityServicePermission()) {
- notifyError(null, PictureProfile.ERROR_NO_PERMISSION,
+ notifyOnPictureProfileError(null, PictureProfile.ERROR_NO_PERMISSION,
Binder.getCallingUid(), Binder.getCallingPid());
}
String [] column = {BaseParameters.PARAMETER_PACKAGE};
@@ -294,13 +323,31 @@ public class MediaQualityService extends SystemService {
}
@Override
- public List<PictureProfileHandle> getPictureProfileHandle(String[] id, UserHandle user) {
- return new ArrayList<>();
+ public List<PictureProfileHandle> getPictureProfileHandle(String[] ids, UserHandle user) {
+ List<PictureProfileHandle> toReturn = new ArrayList<>();
+ for (String id : ids) {
+ Long key = mPictureProfileTempIdMap.getKey(id);
+ if (key != null) {
+ toReturn.add(new PictureProfileHandle(key));
+ } else {
+ toReturn.add(null);
+ }
+ }
+ return toReturn;
}
@Override
- public List<SoundProfileHandle> getSoundProfileHandle(String[] id, UserHandle user) {
- return new ArrayList<>();
+ public List<SoundProfileHandle> getSoundProfileHandle(String[] ids, UserHandle user) {
+ List<SoundProfileHandle> toReturn = new ArrayList<>();
+ for (String id : ids) {
+ Long key = mSoundProfileTempIdMap.getKey(id);
+ if (key != null) {
+ toReturn.add(new SoundProfileHandle(key));
+ } else {
+ toReturn.add(null);
+ }
+ }
+ return toReturn;
}
@Override
@@ -308,8 +355,8 @@ public class MediaQualityService extends SystemService {
if ((sp.getPackageName() != null && !sp.getPackageName().isEmpty()
&& !incomingPackageEqualsCallingUidPackage(sp.getPackageName()))
&& !hasGlobalPictureQualityServicePermission()) {
- //TODO: error handling
- return null;
+ notifyOnSoundProfileError(null, SoundProfile.ERROR_NO_PERMISSION,
+ Binder.getCallingUid(), Binder.getCallingPid());
}
SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
@@ -325,17 +372,18 @@ public class MediaQualityService extends SystemService {
Long id = db.insert(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME,
null, values);
populateTempIdMap(mSoundProfileTempIdMap, id);
- sp.setProfileId(mSoundProfileTempIdMap.getValue(id));
+ String value = mSoundProfileTempIdMap.getValue(id);
+ sp.setProfileId(value);
+ notifyOnSoundProfileAdded(value, sp, Binder.getCallingUid(), Binder.getCallingPid());
return sp;
}
@Override
public void updateSoundProfile(String id, SoundProfile sp, UserHandle user) {
Long dbId = mSoundProfileTempIdMap.getKey(id);
-
if (!hasPermissionToUpdateSoundProfile(dbId, sp)) {
- //TODO: error handling
- return;
+ notifyOnSoundProfileError(id, SoundProfile.ERROR_NO_PERMISSION,
+ Binder.getCallingUid(), Binder.getCallingPid());
}
ContentValues values = getContentValues(dbId,
@@ -347,6 +395,8 @@ public class MediaQualityService extends SystemService {
SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
db.replace(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, null, values);
+ notifyOnSoundProfileUpdated(mSoundProfileTempIdMap.getValue(dbId),
+ getSoundProfile(dbId), Binder.getCallingUid(), Binder.getCallingPid());
}
private boolean hasPermissionToUpdateSoundProfile(Long dbId, SoundProfile sp) {
@@ -359,28 +409,34 @@ public class MediaQualityService extends SystemService {
@Override
public void removeSoundProfile(String id, UserHandle user) {
- Long intId = mSoundProfileTempIdMap.getKey(id);
- if (!hasPermissionToRemoveSoundProfile(intId)) {
- //TODO: error handling
- return;
+ Long dbId = mSoundProfileTempIdMap.getKey(id);
+ SoundProfile toDelete = getSoundProfile(dbId);
+ if (!hasPermissionToRemoveSoundProfile(toDelete)) {
+ notifyOnSoundProfileError(id, SoundProfile.ERROR_NO_PERMISSION,
+ Binder.getCallingUid(), Binder.getCallingPid());
}
- if (intId != null) {
+ if (dbId != null) {
SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
String selection = BaseParameters.PARAMETER_ID + " = ?";
- String[] selectionArgs = {Long.toString(intId)};
+ String[] selectionArgs = {Long.toString(dbId)};
int result = db.delete(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, selection,
selectionArgs);
if (result == 0) {
- //TODO: error handling
+ notifyOnSoundProfileError(id, SoundProfile.ERROR_INVALID_ARGUMENT,
+ Binder.getCallingUid(), Binder.getCallingPid());
}
- mSoundProfileTempIdMap.remove(intId);
+ notifyOnSoundProfileRemoved(mSoundProfileTempIdMap.getValue(dbId), toDelete,
+ Binder.getCallingUid(), Binder.getCallingPid());
+ mSoundProfileTempIdMap.remove(dbId);
}
}
- private boolean hasPermissionToRemoveSoundProfile(Long dbId) {
- SoundProfile fromDb = getSoundProfile(dbId);
- return fromDb.getName().equalsIgnoreCase(getPackageOfCallingUid());
+ private boolean hasPermissionToRemoveSoundProfile(SoundProfile toDelete) {
+ if (toDelete != null) {
+ return toDelete.getName().equalsIgnoreCase(getPackageOfCallingUid());
+ }
+ return false;
}
@Override
@@ -403,7 +459,7 @@ public class MediaQualityService extends SystemService {
return null;
}
if (count > 1) {
- Log.wtf(TAG, String.format(Locale.US, "%d entries found for id=%s"
+ Log.wtf(TAG, String.format(Locale.US, "%d entries found for name=%s"
+ " in %s. Should only ever be 0 or 1.", count, name,
mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME));
return null;
@@ -441,8 +497,8 @@ public class MediaQualityService extends SystemService {
public List<SoundProfile> getSoundProfilesByPackage(
String packageName, Bundle options, UserHandle user) {
if (!hasGlobalSoundQualityServicePermission()) {
- //TODO: error handling
- return new ArrayList<>();
+ notifyOnSoundProfileError(null, SoundProfile.ERROR_NO_PERMISSION,
+ Binder.getCallingUid(), Binder.getCallingPid());
}
boolean includeParams =
@@ -465,8 +521,8 @@ public class MediaQualityService extends SystemService {
@Override
public boolean setDefaultSoundProfile(String profileId, UserHandle user) {
if (!hasGlobalSoundQualityServicePermission()) {
- //TODO: error handling
- return false;
+ notifyOnSoundProfileError(profileId, SoundProfile.ERROR_NO_PERMISSION,
+ Binder.getCallingUid(), Binder.getCallingPid());
}
// TODO: pass the profile ID to MediaQuality HAL when ready.
return false;
@@ -475,8 +531,8 @@ public class MediaQualityService extends SystemService {
@Override
public List<String> getSoundProfilePackageNames(UserHandle user) {
if (!hasGlobalSoundQualityServicePermission()) {
- //TODO: error handling
- return new ArrayList<>();
+ notifyOnSoundProfileError(null, SoundProfile.ERROR_NO_PERMISSION,
+ Binder.getCallingUid(), Binder.getCallingPid());
}
String [] column = {BaseParameters.PARAMETER_NAME};
List<SoundProfile> soundProfiles = getSoundProfilesBasedOnConditions(column,
@@ -718,23 +774,134 @@ public class MediaQualityService extends SystemService {
}
}
- private void notifyError(String profileId, int errorCode, int uid, int pid) {
+ enum Mode {
+ ADD,
+ UPDATE,
+ REMOVE,
+ ERROR
+ }
+
+ private void notifyOnPictureProfileAdded(String profileId, PictureProfile profile,
+ int uid, int pid) {
+ notifyPictureProfileHelper(Mode.ADD, profileId, profile, null, uid, pid);
+ }
+
+ private void notifyOnPictureProfileUpdated(String profileId, PictureProfile profile,
+ int uid, int pid) {
+ notifyPictureProfileHelper(Mode.UPDATE, profileId, profile, null, uid, pid);
+ }
+
+ private void notifyOnPictureProfileRemoved(String profileId, PictureProfile profile,
+ int uid, int pid) {
+ notifyPictureProfileHelper(Mode.REMOVE, profileId, profile, null, uid, pid);
+ }
+
+ private void notifyOnPictureProfileError(String profileId, int errorCode,
+ int uid, int pid) {
+ notifyPictureProfileHelper(Mode.ERROR, profileId, null, errorCode, uid, pid);
+ }
+
+ private void notifyPictureProfileHelper(Mode mode, String profileId, PictureProfile profile,
+ Integer errorCode, int uid, int pid) {
+ UserState userState = getOrCreateUserStateLocked(UserHandle.USER_SYSTEM);
+ int n = userState.mPictureProfileCallbacks.beginBroadcast();
+
+ for (int i = 0; i < n; ++i) {
+ try {
+ IPictureProfileCallback callback = userState.mPictureProfileCallbacks
+ .getBroadcastItem(i);
+ Pair<Integer, Integer> pidUid = userState.mPictureProfileCallbackPidUidMap
+ .get(callback);
+
+ if (pidUid.first == pid && pidUid.second == uid) {
+ if (mode == Mode.ADD) {
+ userState.mPictureProfileCallbacks.getBroadcastItem(i)
+ .onPictureProfileAdded(profileId, profile);
+ } else if (mode == Mode.UPDATE) {
+ userState.mPictureProfileCallbacks.getBroadcastItem(i)
+ .onPictureProfileUpdated(profileId, profile);
+ } else if (mode == Mode.REMOVE) {
+ userState.mPictureProfileCallbacks.getBroadcastItem(i)
+ .onPictureProfileRemoved(profileId, profile);
+ } else if (mode == Mode.ERROR) {
+ userState.mPictureProfileCallbacks.getBroadcastItem(i)
+ .onError(profileId, errorCode);
+ }
+ }
+ } catch (RemoteException e) {
+ if (mode == Mode.ADD) {
+ Slog.e(TAG, "Failed to report added picture profile to callback", e);
+ } else if (mode == Mode.UPDATE) {
+ Slog.e(TAG, "Failed to report updated picture profile to callback", e);
+ } else if (mode == Mode.REMOVE) {
+ Slog.e(TAG, "Failed to report removed picture profile to callback", e);
+ } else if (mode == Mode.ERROR) {
+ Slog.e(TAG, "Failed to report picture profile error to callback", e);
+ }
+ }
+ }
+ userState.mPictureProfileCallbacks.finishBroadcast();
+ }
+
+ private void notifyOnSoundProfileAdded(String profileId, SoundProfile profile,
+ int uid, int pid) {
+ notifySoundProfileHelper(Mode.ADD, profileId, profile, null, uid, pid);
+ }
+
+ private void notifyOnSoundProfileUpdated(String profileId, SoundProfile profile,
+ int uid, int pid) {
+ notifySoundProfileHelper(Mode.UPDATE, profileId, profile, null, uid, pid);
+ }
+
+ private void notifyOnSoundProfileRemoved(String profileId, SoundProfile profile,
+ int uid, int pid) {
+ notifySoundProfileHelper(Mode.REMOVE, profileId, profile, null, uid, pid);
+ }
+
+ private void notifyOnSoundProfileError(String profileId, int errorCode, int uid, int pid) {
+ notifySoundProfileHelper(Mode.ERROR, profileId, null, errorCode, uid, pid);
+ }
+
+ private void notifySoundProfileHelper(Mode mode, String profileId, SoundProfile profile,
+ Integer errorCode, int uid, int pid) {
UserState userState = getOrCreateUserStateLocked(UserHandle.USER_SYSTEM);
- int n = userState.mCallbacks.beginBroadcast();
+ int n = userState.mSoundProfileCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
- IPictureProfileCallback callback = userState.mCallbacks.getBroadcastItem(i);
- Pair<Integer, Integer> pidUid = userState.mCallbackPidUidMap.get(callback);
+ ISoundProfileCallback callback = userState.mSoundProfileCallbacks
+ .getBroadcastItem(i);
+ Pair<Integer, Integer> pidUid = userState.mSoundProfileCallbackPidUidMap
+ .get(callback);
if (pidUid.first == pid && pidUid.second == uid) {
- userState.mCallbacks.getBroadcastItem(i).onError(profileId, errorCode);
+ if (mode == Mode.ADD) {
+ userState.mSoundProfileCallbacks.getBroadcastItem(i)
+ .onSoundProfileAdded(profileId, profile);
+ } else if (mode == Mode.UPDATE) {
+ userState.mSoundProfileCallbacks.getBroadcastItem(i)
+ .onSoundProfileUpdated(profileId, profile);
+ } else if (mode == Mode.REMOVE) {
+ userState.mSoundProfileCallbacks.getBroadcastItem(i)
+ .onSoundProfileRemoved(profileId, profile);
+ } else if (mode == Mode.ERROR) {
+ userState.mSoundProfileCallbacks.getBroadcastItem(i)
+ .onError(profileId, errorCode);
+ }
}
} catch (RemoteException e) {
- Slog.e(TAG, "failed to report added input to callback", e);
+ if (mode == Mode.ADD) {
+ Slog.e(TAG, "Failed to report added sound profile to callback", e);
+ } else if (mode == Mode.UPDATE) {
+ Slog.e(TAG, "Failed to report updated sound profile to callback", e);
+ } else if (mode == Mode.REMOVE) {
+ Slog.e(TAG, "Failed to report removed sound profile to callback", e);
+ } else if (mode == Mode.ERROR) {
+ Slog.e(TAG, "Failed to report sound profile error to callback", e);
+ }
}
}
- userState.mCallbacks.finishBroadcast();
+ userState.mSoundProfileCallbacks.finishBroadcast();
}
@Override
@@ -743,33 +910,102 @@ public class MediaQualityService extends SystemService {
int callingUid = Binder.getCallingUid();
UserState userState = getOrCreateUserStateLocked(Binder.getCallingUid());
- userState.mCallbackPidUidMap.put(callback, Pair.create(callingPid, callingUid));
+ userState.mPictureProfileCallbackPidUidMap.put(callback,
+ Pair.create(callingPid, callingUid));
}
@Override
public void registerSoundProfileCallback(final ISoundProfileCallback callback) {
+ int callingPid = Binder.getCallingPid();
+ int callingUid = Binder.getCallingUid();
+
+ UserState userState = getOrCreateUserStateLocked(Binder.getCallingUid());
+ userState.mSoundProfileCallbackPidUidMap.put(callback,
+ Pair.create(callingPid, callingUid));
}
@Override
public void registerAmbientBacklightCallback(IAmbientBacklightCallback callback) {
+ if (DEBUG) {
+ Slogf.d(TAG, "registerAmbientBacklightCallback");
+ }
+
if (!hasReadColorZonesPermission()) {
//TODO: error handling
}
+
+ String callingPackageName = getPackageOfCallingUid();
+
+ synchronized (mCallbackRecords) {
+ AmbientBacklightCallbackRecord record = mCallbackRecords.get(callingPackageName);
+ if (record != null) {
+ if (record.mCallback.asBinder().equals(callback.asBinder())) {
+ Slog.w(TAG, "AmbientBacklight Callback already registered");
+ return;
+ }
+ record.release();
+ mCallbackRecords.remove(callingPackageName);
+ }
+ mCallbackRecords.put(callingPackageName,
+ new AmbientBacklightCallbackRecord(callingPackageName, callback));
+ }
}
@Override
public void setAmbientBacklightSettings(
AmbientBacklightSettings settings, UserHandle user) {
+ if (DEBUG) {
+ Slogf.d(TAG, "setAmbientBacklightSettings " + settings);
+ }
+
if (!hasReadColorZonesPermission()) {
//TODO: error handling
}
+
+ try {
+ if (mMediaQuality != null) {
+ android.hardware.tv.mediaquality.AmbientBacklightSettings halSettings =
+ new android.hardware.tv.mediaquality.AmbientBacklightSettings();
+ halSettings.uid = Binder.getCallingUid();
+ halSettings.source = (byte) settings.getSource();
+ halSettings.maxFramerate = settings.getMaxFps();
+ halSettings.colorFormat = (byte) settings.getColorFormat();
+ halSettings.hZonesNumber = settings.getHorizontalZonesCount();
+ halSettings.vZonesNumber = settings.getVerticalZonesCount();
+ halSettings.hasLetterbox = settings.isLetterboxOmitted();
+ halSettings.colorThreshold = settings.getThreshold();
+
+ mMediaQuality.setAmbientBacklightDetector(halSettings);
+
+ mHalAmbientBacklightCallback.setAmbientBacklightClientPackageName(
+ getPackageOfCallingUid());
+
+ if (DEBUG) {
+ Slogf.d(TAG, "set ambient settings package: " + halSettings.uid);
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to set ambient backlight settings", e);
+ }
}
@Override
public void setAmbientBacklightEnabled(boolean enabled, UserHandle user) {
+ if (DEBUG) {
+ Slogf.d(TAG, "setAmbientBacklightEnabled " + enabled);
+ }
if (!hasReadColorZonesPermission()) {
//TODO: error handling
}
+ try {
+ if (mMediaQuality != null) {
+ mMediaQuality.setAmbientBacklightDetectionEnabled(enabled);
+ }
+ } catch (UnsupportedOperationException e) {
+ Slog.e(TAG, "The current device is not supported");
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to set ambient backlight enabled", e);
+ }
}
@Override
@@ -781,8 +1017,8 @@ public class MediaQualityService extends SystemService {
@Override
public List<String> getPictureProfileAllowList(UserHandle user) {
if (!hasGlobalPictureQualityServicePermission()) {
- //TODO: error handling
- return new ArrayList<>();
+ notifyOnPictureProfileError(null, PictureProfile.ERROR_NO_PERMISSION,
+ Binder.getCallingUid(), Binder.getCallingPid());
}
return new ArrayList<>();
}
@@ -790,15 +1026,16 @@ public class MediaQualityService extends SystemService {
@Override
public void setPictureProfileAllowList(List<String> packages, UserHandle user) {
if (!hasGlobalPictureQualityServicePermission()) {
- //TODO: error handling
+ notifyOnPictureProfileError(null, PictureProfile.ERROR_NO_PERMISSION,
+ Binder.getCallingUid(), Binder.getCallingPid());
}
}
@Override
public List<String> getSoundProfileAllowList(UserHandle user) {
if (!hasGlobalSoundQualityServicePermission()) {
- //TODO: error handling
- return new ArrayList<>();
+ notifyOnSoundProfileError(null, SoundProfile.ERROR_NO_PERMISSION,
+ Binder.getCallingUid(), Binder.getCallingPid());
}
return new ArrayList<>();
}
@@ -806,7 +1043,8 @@ public class MediaQualityService extends SystemService {
@Override
public void setSoundProfileAllowList(List<String> packages, UserHandle user) {
if (!hasGlobalSoundQualityServicePermission()) {
- //TODO: error handling
+ notifyOnSoundProfileError(null, SoundProfile.ERROR_NO_PERMISSION,
+ Binder.getCallingUid(), Binder.getCallingPid());
}
}
@@ -818,7 +1056,8 @@ public class MediaQualityService extends SystemService {
@Override
public void setAutoPictureQualityEnabled(boolean enabled, UserHandle user) {
if (!hasGlobalPictureQualityServicePermission()) {
- //TODO: error handling
+ notifyOnPictureProfileError(null, PictureProfile.ERROR_NO_PERMISSION,
+ Binder.getCallingUid(), Binder.getCallingPid());
}
try {
@@ -849,7 +1088,8 @@ public class MediaQualityService extends SystemService {
@Override
public void setSuperResolutionEnabled(boolean enabled, UserHandle user) {
if (!hasGlobalPictureQualityServicePermission()) {
- //TODO: error handling
+ notifyOnPictureProfileError(null, PictureProfile.ERROR_NO_PERMISSION,
+ Binder.getCallingUid(), Binder.getCallingPid());
}
try {
@@ -880,7 +1120,8 @@ public class MediaQualityService extends SystemService {
@Override
public void setAutoSoundQualityEnabled(boolean enabled, UserHandle user) {
if (!hasGlobalSoundQualityServicePermission()) {
- //TODO: error handling
+ notifyOnSoundProfileError(null, SoundProfile.ERROR_NO_PERMISSION,
+ Binder.getCallingUid(), Binder.getCallingPid());
}
try {
@@ -914,7 +1155,7 @@ public class MediaQualityService extends SystemService {
}
}
- private class MediaQualityManagerCallbackList extends
+ private class MediaQualityManagerPictureProfileCallbackList extends
RemoteCallbackList<IPictureProfileCallback> {
@Override
public void onCallbackDied(IPictureProfileCallback callback) {
@@ -922,13 +1163,27 @@ public class MediaQualityService extends SystemService {
}
}
+ private class MediaQualityManagerSoundProfileCallbackList extends
+ RemoteCallbackList<ISoundProfileCallback> {
+ @Override
+ public void onCallbackDied(ISoundProfileCallback callback) {
+ //todo
+ }
+ }
+
private final class UserState {
// A list of callbacks.
- private final MediaQualityManagerCallbackList mCallbacks =
- new MediaQualityManagerCallbackList();
+ private final MediaQualityManagerPictureProfileCallbackList mPictureProfileCallbacks =
+ new MediaQualityManagerPictureProfileCallbackList();
+
+ private final MediaQualityManagerSoundProfileCallbackList mSoundProfileCallbacks =
+ new MediaQualityManagerSoundProfileCallbackList();
+
+ private final Map<IPictureProfileCallback, Pair<Integer, Integer>>
+ mPictureProfileCallbackPidUidMap = new HashMap<>();
- private final Map<IPictureProfileCallback, Pair<Integer, Integer>> mCallbackPidUidMap =
- new HashMap<>();
+ private final Map<ISoundProfileCallback, Pair<Integer, Integer>>
+ mSoundProfileCallbackPidUidMap = new HashMap<>();
private UserState(Context context, int userId) {
@@ -947,4 +1202,167 @@ public class MediaQualityService extends SystemService {
private UserState getUserStateLocked(int userId) {
return mUserStates.get(userId);
}
+
+ private final class AmbientBacklightCallbackRecord implements IBinder.DeathRecipient {
+ final String mPackageName;
+ final IAmbientBacklightCallback mCallback;
+
+ AmbientBacklightCallbackRecord(@NonNull String pkgName,
+ @NonNull IAmbientBacklightCallback cb) {
+ mPackageName = pkgName;
+ mCallback = cb;
+ try {
+ mCallback.asBinder().linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to link to death", e);
+ }
+ }
+
+ void release() {
+ try {
+ mCallback.asBinder().unlinkToDeath(this, 0);
+ } catch (NoSuchElementException e) {
+ Slog.e(TAG, "Failed to unlink to death", e);
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ synchronized (mCallbackRecords) {
+ mCallbackRecords.remove(mPackageName);
+ }
+ }
+ }
+
+ private final class HalAmbientBacklightCallback
+ extends android.hardware.tv.mediaquality.IMediaQualityCallback.Stub {
+ private final Object mLock = new Object();
+ private String mAmbientBacklightClientPackageName;
+
+ void setAmbientBacklightClientPackageName(@NonNull String packageName) {
+ synchronized (mLock) {
+ if (TextUtils.equals(mAmbientBacklightClientPackageName, packageName)) {
+ return;
+ }
+ handleAmbientBacklightInterrupted();
+ mAmbientBacklightClientPackageName = packageName;
+ }
+ }
+
+ void handleAmbientBacklightInterrupted() {
+ synchronized (mCallbackRecords) {
+ if (mAmbientBacklightClientPackageName == null) {
+ Slog.e(TAG, "Invalid package name in interrupted event");
+ return;
+ }
+ AmbientBacklightCallbackRecord record = mCallbackRecords.get(
+ mAmbientBacklightClientPackageName);
+ if (record == null) {
+ Slog.e(TAG, "Callback record not found for ambient backlight");
+ return;
+ }
+ AmbientBacklightEvent event =
+ new AmbientBacklightEvent(
+ AMBIENT_BACKLIGHT_EVENT_INTERRUPTED, null);
+ try {
+ record.mCallback.onAmbientBacklightEvent(event);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Deliver ambient backlight interrupted event failed", e);
+ }
+ }
+ }
+
+ void handleAmbientBacklightEnabled(boolean enabled) {
+ AmbientBacklightEvent event =
+ new AmbientBacklightEvent(
+ enabled ? AMBIENT_BACKLIGHT_EVENT_ENABLED :
+ AMBIENT_BACKLIGHT_EVENT_DISABLED, null);
+ synchronized (mCallbackRecords) {
+ for (AmbientBacklightCallbackRecord record : mCallbackRecords.values()) {
+ try {
+ record.mCallback.onAmbientBacklightEvent(event);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Deliver ambient backlight enabled event failed", e);
+ }
+ }
+ }
+ }
+
+ void handleAmbientBacklightMetadataEvent(
+ @NonNull android.hardware.tv.mediaquality.AmbientBacklightMetadata
+ halMetadata) {
+ String halPackageName = mContext.getPackageManager()
+ .getNameForUid(halMetadata.settings.uid);
+ if (!TextUtils.equals(mAmbientBacklightClientPackageName, halPackageName)) {
+ Slog.e(TAG, "Invalid package name in metadata event");
+ return;
+ }
+
+ AmbientBacklightColorFormat[] zonesColorsUnion = halMetadata.zonesColors;
+ int[] zonesColorsInt = new int[zonesColorsUnion.length];
+
+ for (int i = 0; i < zonesColorsUnion.length; i++) {
+ zonesColorsInt[i] = zonesColorsUnion[i].RGB888;
+ }
+
+ AmbientBacklightMetadata metadata =
+ new AmbientBacklightMetadata(
+ halPackageName,
+ halMetadata.compressAlgorithm,
+ halMetadata.settings.source,
+ halMetadata.settings.colorFormat,
+ halMetadata.settings.hZonesNumber,
+ halMetadata.settings.vZonesNumber,
+ zonesColorsInt);
+ AmbientBacklightEvent event =
+ new AmbientBacklightEvent(
+ AMBIENT_BACKLIGHT_EVENT_METADATA_AVAILABLE, metadata);
+
+ synchronized (mCallbackRecords) {
+ AmbientBacklightCallbackRecord record = mCallbackRecords
+ .get(halPackageName);
+ if (record == null) {
+ Slog.e(TAG, "Callback record not found for ambient backlight metadata");
+ return;
+ }
+
+ try {
+ record.mCallback.onAmbientBacklightEvent(event);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Deliver ambient backlight metadata event failed", e);
+ }
+ }
+ }
+
+ @Override
+ public void notifyAmbientBacklightEvent(
+ android.hardware.tv.mediaquality.AmbientBacklightEvent halEvent) {
+ synchronized (mLock) {
+ if (halEvent.getTag() == android.hardware.tv.mediaquality
+ .AmbientBacklightEvent.Tag.enabled) {
+ boolean enabled = halEvent.getEnabled();
+ if (enabled) {
+ handleAmbientBacklightEnabled(true);
+ } else {
+ handleAmbientBacklightEnabled(false);
+ }
+ } else if (halEvent.getTag() == android.hardware.tv.mediaquality
+ .AmbientBacklightEvent.Tag.metadata) {
+ handleAmbientBacklightMetadataEvent(halEvent.getMetadata());
+ } else {
+ Slog.e(TAG, "Invalid event type in ambient backlight event");
+ }
+ }
+ }
+
+ @Override
+ public synchronized String getInterfaceHash() throws android.os.RemoteException {
+ return android.hardware.tv.mediaquality.IMediaQualityCallback.Stub.HASH;
+ }
+
+ @Override
+ public int getInterfaceVersion() throws android.os.RemoteException {
+ return android.hardware.tv.mediaquality.IMediaQualityCallback.Stub.VERSION;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 341038f878d9..adf6c1b94fbd 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -27,6 +27,7 @@ import static android.app.AppOpsManager.OP_RECEIVE_SENSITIVE_NOTIFICATIONS;
import static android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR;
import static android.app.Flags.lifetimeExtensionRefactor;
import static android.app.Flags.notificationClassificationUi;
+import static android.app.Flags.redactSensitiveContentNotificationsOnLockscreen;
import static android.app.Flags.sortSectionByTime;
import static android.app.Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
import static android.app.Notification.EXTRA_BUILDER_APPLICATION_INFO;
@@ -158,6 +159,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.contentprotection.flags.Flags.rapidClearNotificationsByListenerAppOpEnabled;
import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
+import static com.android.internal.util.FrameworkStatsLog.NOTIFICATION_BUNDLE_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES;
@@ -253,6 +255,10 @@ import android.content.pm.VersionedPackage;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.metrics.LogMaker;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -362,6 +368,7 @@ import com.android.server.lights.LightsManager;
import com.android.server.notification.GroupHelper.NotificationAttributes;
import com.android.server.notification.ManagedServices.ManagedServiceInfo;
import com.android.server.notification.ManagedServices.UserProfiles;
+import com.android.server.notification.NotificationRecordLogger.NotificationPullStatsEvent;
import com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent;
import com.android.server.notification.toast.CustomToastRecord;
import com.android.server.notification.toast.TextToastRecord;
@@ -654,6 +661,7 @@ public class NotificationManagerService extends SystemService {
private UsageStatsManagerInternal mUsageStatsManagerInternal;
private TelecomManager mTelecomManager;
private PowerManager mPowerManager;
+ private ConnectivityManager mConnectivityManager;
private PostNotificationTrackerFactory mPostNotificationTrackerFactory;
private LockPatternUtils mLockUtils;
@@ -754,6 +762,7 @@ public class NotificationManagerService extends SystemService {
private int mWarnRemoteViewsSizeBytes;
private int mStripRemoteViewsSizeBytes;
+ private String[] mDefaultUnsupportedAdjustments;
@VisibleForTesting
protected boolean mShowReviewPermissionsNotification;
@@ -775,6 +784,8 @@ public class NotificationManagerService extends SystemService {
private ModuleInfo mAdservicesModuleInfo;
+ private boolean mConnectedToWifi;
+
static class Archive {
final SparseArray<Boolean> mEnabled;
final int mBufferSize;
@@ -2571,6 +2582,7 @@ public class NotificationManagerService extends SystemService {
TelecomManager telecomManager, NotificationChannelLogger channelLogger,
SystemUiSystemPropertiesFlags.FlagResolver flagResolver,
PermissionManager permissionManager, PowerManager powerManager,
+ ConnectivityManager connectivityManager,
PostNotificationTrackerFactory postNotificationTrackerFactory) {
mHandler = handler;
Resources resources = getContext().getResources();
@@ -2603,6 +2615,8 @@ public class NotificationManagerService extends SystemService {
mUm = userManager;
mTelecomManager = telecomManager;
mPowerManager = powerManager;
+ mConnectivityManager = connectivityManager;
+ registerNetworkCallback();
mPostNotificationTrackerFactory = postNotificationTrackerFactory;
mPlatformCompat = IPlatformCompat.Stub.asInterface(
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
@@ -2818,6 +2832,36 @@ public class NotificationManagerService extends SystemService {
mAppOps.startWatchingMode(AppOpsManager.OP_POST_NOTIFICATION, null, mAppOpsListener);
}
+ private void registerNetworkCallback() {
+ NetworkRequest request = new NetworkRequest.Builder().addTransportType(
+ NetworkCapabilities.TRANSPORT_WIFI).build();
+ mConnectivityManager.registerNetworkCallback(request,
+ new ConnectivityManager.NetworkCallback() {
+ // Need to post to another thread, as we can't call synchronous ConnectivityManager
+ // methods from the callback itself, due to potential race conditions.
+ @Override
+ public void onAvailable(@NonNull Network network) {
+ mHandler.post(() -> updateWifiConnectionState());
+ }
+ @Override
+ public void onLost(@NonNull Network network) {
+ mHandler.post(() -> updateWifiConnectionState());
+ }
+ });
+ updateWifiConnectionState();
+ }
+
+ @VisibleForTesting()
+ void updateWifiConnectionState() {
+ Network current = mConnectivityManager.getActiveNetwork();
+ NetworkCapabilities capabilities = mConnectivityManager.getNetworkCapabilities(current);
+ if (current == null || capabilities == null) {
+ mConnectedToWifi = false;
+ return;
+ }
+ mConnectedToWifi = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
+ }
+
/**
* Cleanup broadcast receivers change listeners.
*/
@@ -2856,6 +2900,7 @@ public class NotificationManagerService extends SystemService {
mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_PREFERENCES);
mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES);
mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES);
+ mStatsManager.clearPullAtomCallback(NOTIFICATION_BUNDLE_PREFERENCES);
mStatsManager.clearPullAtomCallback(DND_MODE_RULE);
}
if (mAppOps != null) {
@@ -2894,6 +2939,9 @@ public class NotificationManagerService extends SystemService {
mShowReviewPermissionsNotification = getContext().getResources().getBoolean(
R.bool.config_notificationReviewPermissions);
+ mDefaultUnsupportedAdjustments = getContext().getResources().getStringArray(
+ R.array.config_notificationDefaultUnsupportedAdjustments);
+
init(handler, new RankingHandlerWorker(mRankingThread.getLooper()),
AppGlobals.getPackageManager(), getContext().getPackageManager(),
getLocalService(LightsManager.class),
@@ -2927,6 +2975,7 @@ public class NotificationManagerService extends SystemService {
new NotificationChannelLoggerImpl(), SystemUiSystemPropertiesFlags.getResolver(),
getContext().getSystemService(PermissionManager.class),
getContext().getSystemService(PowerManager.class),
+ getContext().getSystemService(ConnectivityManager.class),
new PostNotificationTrackerFactory() {});
publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
@@ -2960,6 +3009,12 @@ public class NotificationManagerService extends SystemService {
ConcurrentUtils.DIRECT_EXECUTOR,
mPullAtomCallback
);
+ mStatsManager.setPullAtomCallback(
+ NOTIFICATION_BUNDLE_PREFERENCES,
+ null, // use default PullAtomMetadata values
+ ConcurrentUtils.DIRECT_EXECUTOR,
+ mPullAtomCallback
+ );
}
private class StatsPullAtomCallbackImpl implements StatsManager.StatsPullAtomCallback {
@@ -2969,6 +3024,7 @@ public class NotificationManagerService extends SystemService {
case PACKAGE_NOTIFICATION_PREFERENCES:
case PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES:
case PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES:
+ case NOTIFICATION_BUNDLE_PREFERENCES:
case DND_MODE_RULE:
return pullNotificationStates(atomTag, data);
default:
@@ -2980,8 +3036,15 @@ public class NotificationManagerService extends SystemService {
private int pullNotificationStates(int atomTag, List<StatsEvent> data) {
switch(atomTag) {
case PACKAGE_NOTIFICATION_PREFERENCES:
- mPreferencesHelper.pullPackagePreferencesStats(data,
- getAllUsersNotificationPermissions());
+ if (notificationClassificationUi()) {
+ Set<String> pkgs = mAssistants.getPackagesWithKeyTypeAdjustmentSettings();
+ mPreferencesHelper.pullPackagePreferencesStats(data,
+ getAllUsersNotificationPermissions(),
+ getPackageSpecificAdjustmentKeyTypes(pkgs));
+ } else {
+ mPreferencesHelper.pullPackagePreferencesStats(data,
+ getAllUsersNotificationPermissions());
+ }
break;
case PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES:
mPreferencesHelper.pullPackageChannelPreferencesStats(data);
@@ -2989,6 +3052,11 @@ public class NotificationManagerService extends SystemService {
case PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES:
mPreferencesHelper.pullPackageChannelGroupPreferencesStats(data);
break;
+ case NOTIFICATION_BUNDLE_PREFERENCES:
+ if (notificationClassification() && notificationClassificationUi()) {
+ mAssistants.pullBundlePreferencesStats(data);
+ }
+ break;
case DND_MODE_RULE:
mZenModeHelper.pullRules(data);
break;
@@ -4961,6 +5029,12 @@ public class NotificationManagerService extends SystemService {
@Override
public ParceledListSlice<NotificationChannel> getNotificationChannels(
String callingPkg, String targetPkg, int userId) {
+ return getOrCreateNotificationChannels(callingPkg, targetPkg, userId, false);
+ }
+
+ @Override
+ public ParceledListSlice<NotificationChannel> getOrCreateNotificationChannels(
+ String callingPkg, String targetPkg, int userId, boolean createPrefsIfNeeded) {
if (canNotifyAsPackage(callingPkg, targetPkg, userId)
|| isCallingUidSystem()) {
int targetUid = -1;
@@ -4970,7 +5044,8 @@ public class NotificationManagerService extends SystemService {
/* ignore */
}
return mPreferencesHelper.getNotificationChannels(
- targetPkg, targetUid, false /* includeDeleted */, true);
+ targetPkg, targetUid, false /* includeDeleted */, true,
+ createPrefsIfNeeded);
}
throw new SecurityException("Pkg " + callingPkg
+ " cannot read channels for " + targetPkg + " in " + userId);
@@ -7481,6 +7556,24 @@ public class NotificationManagerService extends SystemService {
return allPermissions;
}
+ @VisibleForTesting
+ @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ protected @NonNull Map<String, Set<Integer>> getPackageSpecificAdjustmentKeyTypes(
+ Set<String> pkgs) {
+ ArrayMap<String, Set<Integer>> pkgToAllowedTypes = new ArrayMap<>();
+ for (String pkg : pkgs) {
+ int[] allowedTypesArray = mAssistants.getAllowedAdjustmentKeyTypesForPackage(pkg);
+ if (allowedTypesArray != null) {
+ Set<Integer> allowedTypes = new ArraySet<Integer>();
+ for (int i : allowedTypesArray) {
+ allowedTypes.add(i);
+ }
+ pkgToAllowedTypes.append(pkg, allowedTypes);
+ }
+ }
+ return pkgToAllowedTypes;
+ }
+
private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter,
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
JSONObject dump = new JSONObject();
@@ -10388,16 +10481,12 @@ public class NotificationManagerService extends SystemService {
}
private void scheduleListenerHintsChanged(int state) {
- if (!Flags.notificationReduceMessagequeueUsage()) {
- mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
- }
+ mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
}
private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
- if (!Flags.notificationReduceMessagequeueUsage()) {
- mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
- }
+ mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
mHandler.obtainMessage(
MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
listenerInterruptionFilter,
@@ -10477,14 +10566,9 @@ public class NotificationManagerService extends SystemService {
}
protected void scheduleSendRankingUpdate() {
- if (Flags.notificationReduceMessagequeueUsage()) {
+ if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
sendMessage(m);
- } else {
- if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
- Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
- sendMessage(m);
- }
}
}
@@ -10493,12 +10577,8 @@ public class NotificationManagerService extends SystemService {
if (lifetimeExtensionRefactor()) {
sendMessageDelayed(Message.obtain(this, cancelRunnable), delay);
} else {
- if (Flags.notificationReduceMessagequeueUsage()) {
+ if (!hasCallbacks(cancelRunnable)) {
sendMessage(Message.obtain(this, cancelRunnable));
- } else {
- if (!hasCallbacks(cancelRunnable)) {
- sendMessage(Message.obtain(this, cancelRunnable));
- }
}
}
}
@@ -10533,9 +10613,7 @@ public class NotificationManagerService extends SystemService {
}
public void requestSort() {
- if (!Flags.notificationReduceMessagequeueUsage()) {
- removeMessages(MESSAGE_RANKING_SORT);
- }
+ removeMessages(MESSAGE_RANKING_SORT);
Message msg = Message.obtain();
msg.what = MESSAGE_RANKING_SORT;
sendMessage(msg);
@@ -11613,12 +11691,20 @@ public class NotificationManagerService extends SystemService {
new NotificationListenerService.Ranking();
ArrayList<Notification.Action> smartActions = record.getSystemGeneratedSmartActions();
ArrayList<CharSequence> smartReplies = record.getSmartReplies();
- if (redactSensitiveNotificationsFromUntrustedListeners()
- && info != null
- && !mListeners.isUidTrusted(info.uid)
- && mListeners.hasSensitiveContent(record)) {
- smartActions = null;
- smartReplies = null;
+ boolean hasSensitiveContent = record.hasSensitiveContent();
+ if (redactSensitiveNotificationsFromUntrustedListeners()) {
+ if (!mListeners.isUidTrusted(info.uid) && mListeners.hasSensitiveContent(record)) {
+ smartActions = null;
+ smartReplies = null;
+ }
+ if (redactSensitiveContentNotificationsOnLockscreen()) {
+ if (mListeners.hasSensitiveContent(record) && mConnectedToWifi
+ && info.isSystemUi) {
+ // We don't inform systemUI of sensitive content if
+ // connected to wifi, though we do still redact from untrusted listeners.
+ hasSensitiveContent = false;
+ }
+ }
}
ranking.populate(
key,
@@ -11648,7 +11734,7 @@ public class NotificationManagerService extends SystemService {
: (record.getRankingScore() > 0 ? RANKING_PROMOTED : RANKING_DEMOTED),
record.getNotification().isBubbleNotification(),
record.getProposedImportance(),
- record.hasSensitiveContent()
+ hasSensitiveContent
);
rankings.add(ranking);
}
@@ -11908,6 +11994,9 @@ public class NotificationManagerService extends SystemService {
}
} else {
mAllowedAdjustmentKeyTypes.addAll(List.of(DEFAULT_ALLOWED_ADJUSTMENT_KEY_TYPES));
+ if (mDefaultUnsupportedAdjustments != null) {
+ mAllowedAdjustments.removeAll(List.of(mDefaultUnsupportedAdjustments));
+ }
}
}
@@ -12056,6 +12145,22 @@ public class NotificationManagerService extends SystemService {
}
@FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+ protected @NonNull Set<String> getPackagesWithKeyTypeAdjustmentSettings() {
+ if (notificationClassificationUi()) {
+ Set<String> packagesWithModifications = new ArraySet<String>();
+ synchronized (mLock) {
+ for (String pkg : mClassificationTypePackagesEnabledTypes.keySet()) {
+ if (mClassificationTypePackagesEnabledTypes.get(pkg) != null) {
+ packagesWithModifications.add(pkg);
+ }
+ }
+ }
+ return packagesWithModifications;
+ }
+ return new ArraySet<String>();
+ }
+
+ @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
protected @NonNull int[] getAllowedAdjustmentKeyTypesForPackage(String pkg) {
synchronized (mLock) {
if (notificationClassificationUi()) {
@@ -12656,6 +12761,32 @@ public class NotificationManagerService extends SystemService {
Slog.e(TAG, "unable to notify assistant (capabilities): " + info, ex);
}
}
+
+ /**
+ * Fills out {@link BundlePreferences} proto and wraps it in a {@link StatsEvent}.
+ */
+ @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ protected void pullBundlePreferencesStats(List<StatsEvent> events) {
+ boolean bundlesAllowed = true;
+ synchronized (mLock) {
+ List<String> unsupportedAdjustments = new ArrayList(
+ mNasUnsupported.getOrDefault(
+ UserHandle.getUserId(Binder.getCallingUid()),
+ new HashSet<>())
+ );
+ bundlesAllowed = !unsupportedAdjustments.contains(Adjustment.KEY_TYPE);
+ }
+
+ int[] allowedBundleTypes = getAllowedAdjustmentKeyTypes();
+
+ events.add(FrameworkStatsLog.buildStatsEvent(
+ NOTIFICATION_BUNDLE_PREFERENCES,
+ /* optional int32 event_id = 1 */
+ NotificationPullStatsEvent.NOTIFICATION_BUNDLE_PREFERENCES_PULLED.getId(),
+ /* optional bool bundles_allowed = 2 */ bundlesAllowed,
+ /* repeated android.stats.notification.BundleTypes allowed_bundle_types = 3 */
+ allowedBundleTypes));
+ }
}
/**
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
index 3943aa583fee..6c0035b82a86 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
@@ -32,8 +32,6 @@ import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationStats;
import android.util.Log;
-import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
-import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags;
import com.android.internal.logging.InstanceId;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
@@ -368,6 +366,19 @@ interface NotificationRecordLogger {
}
}
+ enum NotificationPullStatsEvent implements UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "Notification Bundle Preferences pulled.")
+ NOTIFICATION_BUNDLE_PREFERENCES_PULLED(2072);
+
+ private final int mId;
+ NotificationPullStatsEvent(int id) {
+ mId = id;
+ }
+ @Override public int getId() {
+ return mId;
+ }
+ }
+
/**
* A helper for extracting logging information from one or two NotificationRecords.
*/
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 36eabae69b22..3b34dcd17705 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
+import static android.app.Flags.notificationClassificationUi;
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
import static android.app.NotificationChannel.NEWS_ID;
@@ -1961,10 +1962,25 @@ public class PreferencesHelper implements RankingConfig {
@Override
public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid,
boolean includeDeleted, boolean includeBundles) {
+ return getNotificationChannels(pkg, uid, includeDeleted, includeBundles, false);
+ }
+
+ protected ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid,
+ boolean includeDeleted, boolean includeBundles, boolean createPrefsIfNeeded) {
+ if (createPrefsIfNeeded && !android.app.Flags.nmBinderPerfCacheChannels()) {
+ Slog.wtf(TAG,
+ "getNotificationChannels called with createPrefsIfNeeded=true and flag off");
+ createPrefsIfNeeded = false;
+ }
Objects.requireNonNull(pkg);
List<NotificationChannel> channels = new ArrayList<>();
synchronized (mLock) {
- PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+ PackagePreferences r;
+ if (createPrefsIfNeeded) {
+ r = getOrCreatePackagePreferencesLocked(pkg, uid);
+ } else {
+ r = getPackagePreferencesLocked(pkg, uid);
+ }
if (r == null) {
return ParceledListSlice.emptyList();
}
@@ -2523,6 +2539,25 @@ public class PreferencesHelper implements RankingConfig {
*/
public void pullPackagePreferencesStats(List<StatsEvent> events,
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
+ pullPackagePreferencesStats(events, pkgPermissions, new ArrayMap<String, Set<Integer>>());
+ }
+
+
+ /**
+ * Fills out {@link PackageNotificationPreferences} proto and wraps it in a {@link StatsEvent}.
+ * @param events Newly filled out StatsEvent protos are added to this list as output.
+ * @param pkgPermissions Maps from a pair representing a uid and package to a pair of booleans,
+ * where the first represents whether the notification permission was
+ * granted to that package, and the second represents whether the
+ * permission was user-set.
+ * @param pkgAdjustmentKeyTypes A map of package names that are not allowed to have their
+ * notifications classified into differently typed notification
+ * channels, and the channels that they're allowed to be
+ * classified into.
+ */
+ public void pullPackagePreferencesStats(List<StatsEvent> events,
+ ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions,
+ @NonNull Map<String, Set<Integer>> pkgAdjustmentKeyTypes) {
Set<Pair<Integer, String>> pkgsWithPermissionsToHandle = null;
if (pkgPermissions != null) {
pkgsWithPermissionsToHandle = pkgPermissions.keySet();
@@ -2568,6 +2603,14 @@ public class PreferencesHelper implements RankingConfig {
isFsiPermissionUserSet(r.pkg, r.uid, fsiState,
currentPermissionFlags);
+ if (!notificationClassificationUi()
+ && pkgAdjustmentKeyTypes.keySet().size() > 0) {
+ Slog.w(TAG, "Pkg adjustment types improperly allowed without flag set");
+ }
+
+ int[] allowedBundleTypes =
+ getAllowedTypesForPackage(pkgAdjustmentKeyTypes, r.pkg);
+
events.add(FrameworkStatsLog.buildStatsEvent(
PACKAGE_NOTIFICATION_PREFERENCES,
/* optional int32 uid = 1 [(is_uid) = true] */ r.uid,
@@ -2576,7 +2619,9 @@ public class PreferencesHelper implements RankingConfig {
/* optional int32 user_locked_fields = 4 */ r.lockedAppFields,
/* optional bool user_set_importance = 5 */ importanceIsUserSet,
/* optional FsiState fsi_state = 6 */ fsiState,
- /* optional bool is_fsi_permission_user_set = 7 */ fsiIsUserSet));
+ /* optional bool is_fsi_permission_user_set = 7 */ fsiIsUserSet,
+ /* repeated int32 allowed_bundle_types = 8 */ allowedBundleTypes
+ ));
}
}
@@ -2587,6 +2632,10 @@ public class PreferencesHelper implements RankingConfig {
break;
}
pulledEvents++;
+
+ int[] allowedBundleTypes =
+ getAllowedTypesForPackage(pkgAdjustmentKeyTypes, p.second);
+
// Because all fields are required in FrameworkStatsLog.buildStatsEvent, we have
// to fill in default values for all the unspecified fields.
events.add(FrameworkStatsLog.buildStatsEvent(
@@ -2598,9 +2647,29 @@ public class PreferencesHelper implements RankingConfig {
/* optional int32 user_locked_fields = 4 */ DEFAULT_LOCKED_APP_FIELDS,
/* optional bool user_set_importance = 5 */ pkgPermissions.get(p).second,
/* optional FsiState fsi_state = 6 */ 0,
- /* optional bool is_fsi_permission_user_set = 7 */ false));
+ /* optional bool is_fsi_permission_user_set = 7 */ false,
+ /* repeated BundleTypes allowed_bundle_types = 8 */ allowedBundleTypes));
+ }
+ }
+ }
+
+ private int[] getAllowedTypesForPackage(@NonNull
+ Map<String, Set<Integer>> pkgAdjustmentKeyTypes,
+ String pkg) {
+ int[] allowedBundleTypes = new int[]{};
+ if (notificationClassificationUi()) {
+ if (pkgAdjustmentKeyTypes.containsKey(pkg)) {
+ // Convert from set to int[]
+ Set<Integer> types = pkgAdjustmentKeyTypes.get(pkg);
+ allowedBundleTypes = new int[types.size()];
+ int i = 0;
+ for (int val : types) {
+ allowedBundleTypes[i] = val;
+ i++;
+ }
}
}
+ return allowedBundleTypes;
}
/**
diff --git a/services/core/java/com/android/server/notification/flags.aconfig b/services/core/java/com/android/server/notification/flags.aconfig
index c1ca9c23aef5..b4a8aee66c7c 100644
--- a/services/core/java/com/android/server/notification/flags.aconfig
+++ b/services/core/java/com/android/server/notification/flags.aconfig
@@ -51,13 +51,6 @@ flag {
}
flag {
- name: "notification_reduce_messagequeue_usage"
- namespace: "systemui"
- description: "When this flag is on, NMS will no longer call removeMessage() and hasCallbacks() on Handler"
- bug: "311051285"
-}
-
-flag {
name: "notification_test"
namespace: "systemui"
description: "Timing test, no functionality"
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index 3660607d8764..bf0e77e03171 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -86,8 +86,6 @@ import java.util.function.Supplier;
*/
public final class BroadcastHelper {
private static final boolean DEBUG_BROADCASTS = false;
- private static final String PERMISSION_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED =
- "android.permission.INTERNAL_RECEIVE_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED";
private final UserManagerInternal mUmInternal;
private final ActivityManagerInternal mAmInternal;
@@ -398,8 +396,7 @@ public final class BroadcastHelper {
sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp,
notExportedComponentNames, packageUid, reason, userIds, instantUserIds,
broadcastAllowList, "android" /* targetPackageName */,
- new String[]{
- PERMISSION_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED});
+ null /* requiredPermissions */);
}
// Second, send the PACKAGE_CHANGED broadcast to the application itself.
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index f6e518a4fed7..90adb6683496 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -729,10 +729,13 @@ final class DeletePackageHelper {
final String internalPackageName =
snapshot.resolveInternalPackageName(packageName, versionCode);
+ final boolean deleteAllUsers = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0;
+ final int[] users = deleteAllUsers ? mUserManagerInternal.getUserIds() : new int[]{userId};
+
if (!isOrphaned(snapshot, internalPackageName)
&& !allowSilentUninstall
- && !isCallerAllowedToSilentlyUninstall(
- snapshot, callingUid, internalPackageName, userId)) {
+ && !isCallerAllowedToSilentlyUninstall(snapshot, callingUid, internalPackageName,
+ users)) {
mPm.mHandler.post(() -> {
try {
final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
@@ -751,8 +754,7 @@ final class DeletePackageHelper {
});
return;
}
- final boolean deleteAllUsers = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0;
- final int[] users = deleteAllUsers ? mUserManagerInternal.getUserIds() : new int[]{userId};
+
if (UserHandle.getUserId(callingUid) != userId || (deleteAllUsers && users.length > 1)) {
mPm.mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
@@ -916,16 +918,24 @@ final class DeletePackageHelper {
}
private boolean isCallerAllowedToSilentlyUninstall(@NonNull Computer snapshot, int callingUid,
- String pkgName, int userId) {
+ String pkgName, int[] targetUserIds) {
if (PackageManagerServiceUtils.isRootOrShell(callingUid)
|| UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
return true;
}
final int callingUserId = UserHandle.getUserId(callingUid);
+
// If the caller installed the pkgName, then allow it to silently uninstall.
- if (callingUid == snapshot.getPackageUid(
- snapshot.getInstallerPackageName(pkgName, userId), 0, callingUserId)) {
- return true;
+ for (int user : targetUserIds) {
+ try {
+ if (callingUid == snapshot.getPackageUid(
+ snapshot.getInstallerPackageName(pkgName, user), 0, callingUserId)) {
+ return true;
+ }
+ } catch (Exception ignored) {
+ // The app to be uninstalled (`pkgName`) is not installed on this `user`. Continue
+ // looking for the installerPkgName in the next user
+ }
}
// Allow package verifier to silently uninstall.
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index a8f31f90d1e0..4cca85590967 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -3039,13 +3039,14 @@ final class InstallPackageHelper {
if (android.permission.flags.Flags.enhancedConfirmationModeApisEnabled()
&& android.security.Flags.extendEcmToAllSettings()) {
final int appId = request.getAppId();
- mPm.mHandler.post(() -> {
+ // TODO: b/388960315 - Implement a long-term solution to race condition
+ mPm.mHandler.postDelayed(() -> {
for (int userId : firstUserIds) {
// MODE_DEFAULT means that the app's guardedness will be decided lazily
setAccessRestrictedSettingsMode(packageName, appId, userId,
AppOpsManager.MODE_DEFAULT);
}
- });
+ }, 1000L);
} else {
// Apply restricted settings on potentially dangerous packages. Needs to happen
// after appOpsManager is notified of the new package
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f60e086e7c5d..61429a41370c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4255,8 +4255,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService
CarrierAppUtils.disableCarrierAppsUntilPrivileged(
mContext.getOpPackageName(), UserHandle.USER_SYSTEM, mContext);
- disableSkuSpecificApps();
-
// Read the compatibilty setting when the system is ready.
boolean compatibilityModeEnabled = android.provider.Settings.Global.getInt(
mContext.getContentResolver(),
@@ -4390,29 +4388,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
}
- //TODO: b/111402650
- private void disableSkuSpecificApps() {
- String[] apkList = mContext.getResources().getStringArray(
- R.array.config_disableApksUnlessMatchedSku_apk_list);
- String[] skuArray = mContext.getResources().getStringArray(
- R.array.config_disableApkUnlessMatchedSku_skus_list);
- if (ArrayUtils.isEmpty(apkList)) {
- return;
- }
- String sku = SystemProperties.get("ro.boot.hardware.sku");
- if (!TextUtils.isEmpty(sku) && ArrayUtils.contains(skuArray, sku)) {
- return;
- }
- final Computer snapshot = snapshotComputer();
- for (String packageName : apkList) {
- setSystemAppHiddenUntilInstalled(snapshot, packageName, true);
- final List<UserInfo> users = mInjector.getUserManagerInternal().getUsers(false);
- for (int i = 0; i < users.size(); i++) {
- setSystemAppInstallState(snapshot, packageName, false, users.get(i).id);
- }
- }
- }
-
public PackageFreezer freezePackage(String packageName, int userId, String killReason,
int exitInfoReason, InstallRequest request) {
return freezePackage(packageName, userId, killReason, exitInfoReason, request,
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index fb16b862b275..a902f5ff372f 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -1848,8 +1848,10 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
boolean manifestOverrideEnabled = (mPageSizeAppCompatFlags
& ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_MANIFEST_OVERRIDE_ENABLED) != 0;
boolean settingsOverrideEnabled = (mPageSizeAppCompatFlags
- & ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_MANIFEST_OVERRIDE_ENABLED) != 0;
- if (manifestOverrideEnabled || settingsOverrideEnabled) {
+ & ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_SETTINGS_OVERRIDE_ENABLED) != 0;
+ boolean settingsOverrideDisabled = (mPageSizeAppCompatFlags
+ & ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_SETTINGS_OVERRIDE_DISABLED) != 0;
+ if (manifestOverrideEnabled || settingsOverrideEnabled || settingsOverrideDisabled) {
return null;
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 81956fbb55e6..b85e6894b910 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -33,6 +33,7 @@ import static android.os.UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY;
import static android.os.UserManager.USER_OPERATION_ERROR_UNKNOWN;
import static android.os.UserManager.USER_OPERATION_ERROR_USER_RESTRICTED;
import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE;
+import static android.os.UserManager.supportsMultipleUsers;
import static android.provider.Settings.Secure.HIDE_PRIVATESPACE_ENTRY_POINT;
import static com.android.internal.app.SetScreenLockDialogActivity.EXTRA_ORIGIN_USER_ID;
@@ -1156,7 +1157,7 @@ public class UserManagerService extends IUserManager.Stub {
showHsumNotificationIfNeeded();
- if (Flags.addUiForSoundsFromBackgroundUsers()) {
+ if (shouldShowNotificationForBackgroundUserSounds()) {
new BackgroundUserSoundNotifier(mContext);
}
}
@@ -3312,13 +3313,18 @@ public class UserManagerService extends IUserManager.Stub {
}
}
-
-
private void sendUserInfoChangedBroadcast(@UserIdInt int userId) {
Intent changedIntent = new Intent(Intent.ACTION_USER_INFO_CHANGED);
changedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
changedIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcastAsUser(changedIntent, UserHandle.ALL);
+
+ // This intent allow system UI apps to refresh the content even if process was freezed.
+ Intent bgIntent = new Intent(Intent.ACTION_USER_INFO_CHANGED_BACKGROUND);
+ bgIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ bgIntent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ mContext.sendBroadcastAsUser(bgIntent, UserHandle.ALL,
+ Manifest.permission.MANAGE_USERS);
}
@Override
@@ -8481,6 +8487,17 @@ public class UserManagerService extends IUserManager.Stub {
}
/**
+ * @hide
+ * Checks whether to show a notification for sounds (e.g., alarms, timers, etc.) from
+ * background users.
+ */
+ public static boolean shouldShowNotificationForBackgroundUserSounds() {
+ return Flags.addUiForSoundsFromBackgroundUsers() && Resources.getSystem().getBoolean(
+ com.android.internal.R.bool.config_showNotificationForBackgroundUserAlarms)
+ && supportsMultipleUsers();
+ }
+
+ /**
* Returns instance of {@link com.android.server.pm.UserJourneyLogger}.
*/
public UserJourneyLogger getUserJourneyLogger() {
diff --git a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
index e75f852eb437..a755ee1cd0fe 100644
--- a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
+++ b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
@@ -45,6 +45,7 @@ import com.android.server.devicestate.DeviceStateProvider;
import com.android.server.input.InputManagerInternal;
import com.android.server.policy.devicestate.config.Conditions;
import com.android.server.policy.devicestate.config.DeviceStateConfig;
+import com.android.server.policy.devicestate.config.Flags;
import com.android.server.policy.devicestate.config.LidSwitchCondition;
import com.android.server.policy.devicestate.config.NumericRange;
import com.android.server.policy.devicestate.config.Properties;
@@ -140,7 +141,16 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
private static final String PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT =
"com.android.server.policy.PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT";
-
+ // Deprecated flag definitions to maintain backwards compatibility.
+ private static final String FLAG_CANCEL_OVERRIDE_REQUESTS = "FLAG_CANCEL_OVERRIDE_REQUESTS";
+ private static final String FLAG_APP_INACCESSIBLE = "FLAG_APP_INACCESSIBLE";
+ private static final String FLAG_EMULATED_ONLY = "FLAG_EMULATED_ONLY";
+ private static final String FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP =
+ "FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP";
+ private static final String FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL =
+ "FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL";
+ private static final String FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE =
+ "FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE";
/** Interface that allows reading the device state configuration. */
interface ReadableConfig {
@@ -185,15 +195,29 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
new HashSet<>();
Set<@DeviceState.DeviceStateProperties Integer> physicalProperties =
new HashSet<>();
- final Properties configFlags = stateConfig.getProperties();
- if (configFlags != null) {
- List<String> configPropertyStrings = configFlags.getProperty();
+ final Properties configProperties = stateConfig.getProperties();
+ if (configProperties != null) {
+ List<String> configPropertyStrings = configProperties.getProperty();
for (int i = 0; i < configPropertyStrings.size(); i++) {
final String configPropertyString = configPropertyStrings.get(i);
addPropertyByString(configPropertyString, systemProperties,
physicalProperties);
}
}
+
+ if (android.hardware.devicestate.feature.flags
+ .Flags.deviceStateConfigurationFlag()) {
+ // Parse through the deprecated flag configuration to keep compatibility.
+ final Flags configFlags = stateConfig.getFlags();
+ if (configFlags != null) {
+ List<String> configFlagStrings = configFlags.getFlag();
+ for (int i = 0; i < configFlagStrings.size(); i++) {
+ final String configFlagString = configFlagStrings.get(i);
+ addFlagByString(configFlagString, systemProperties);
+ }
+ }
+ }
+
DeviceState.Configuration deviceStateConfiguration =
new DeviceState.Configuration.Builder(state, name)
.setSystemProperties(systemProperties)
@@ -292,6 +316,34 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
}
}
+ private static void addFlagByString(String flagString,
+ Set<@DeviceState.SystemDeviceStateProperties Integer> systemProperties) {
+ switch (flagString) {
+ case FLAG_APP_INACCESSIBLE:
+ systemProperties.add(DeviceState.PROPERTY_APP_INACCESSIBLE);
+ break;
+ case FLAG_EMULATED_ONLY:
+ systemProperties.add(DeviceState.PROPERTY_EMULATED_ONLY);
+ break;
+ case FLAG_CANCEL_OVERRIDE_REQUESTS:
+ systemProperties.add(DeviceState.PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS);
+ break;
+ case FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP:
+ systemProperties.add(DeviceState.PROPERTY_POLICY_CANCEL_WHEN_REQUESTER_NOT_ON_TOP);
+ break;
+ case FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE:
+ systemProperties.add(DeviceState.PROPERTY_POLICY_UNSUPPORTED_WHEN_POWER_SAVE_MODE);
+ break;
+ case FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL:
+ systemProperties.add(
+ DeviceState.PROPERTY_POLICY_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL);
+ break;
+ default:
+ Slog.w(TAG, "Parsed unknown flag with name: " + flagString);
+ break;
+ }
+ }
+
// Lock for internal state.
private final Object mLock = new Object();
private final Context mContext;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index f9e4022f04a0..090707db50a5 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -30,6 +30,7 @@ import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
import static android.os.PowerManagerInternal.isInteractive;
import static android.os.PowerManagerInternal.wakefulnessToString;
+import static android.service.dreams.Flags.allowDreamWhenPostured;
import static com.android.internal.util.LatencyTracker.ACTION_TURN_ON_SCREEN;
import static com.android.server.deviceidle.Flags.disableWakelocksInLightIdle;
@@ -216,6 +217,8 @@ public final class PowerManagerService extends SystemService
private static final int DIRTY_ATTENTIVE = 1 << 14;
// Dirty bit: display group wakefulness has changed
private static final int DIRTY_DISPLAY_GROUP_WAKEFULNESS = 1 << 16;
+ // Dirty bit: device postured state has changed
+ private static final int DIRTY_POSTURED_STATE = 1 << 17;
// Summarizes the state of all active wakelocks.
static final int WAKE_LOCK_CPU = 1 << 0;
@@ -500,6 +503,11 @@ public final class PowerManagerService extends SystemService
// The current dock state.
private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ /**
+ * Whether the device is upright and stationary.
+ */
+ private boolean mDevicePostured;
+
// True to decouple auto-suspend mode from the display state.
private boolean mDecoupleHalAutoSuspendModeFromDisplayConfig;
@@ -530,6 +538,9 @@ public final class PowerManagerService extends SystemService
// Default value for dreams activate-on-dock
private boolean mDreamsActivatedOnDockByDefaultConfig;
+ /** Default value for whether dreams are activated when postured (stationary + upright) */
+ private boolean mDreamsActivatedWhilePosturedByDefaultConfig;
+
// True if dreams can run while not plugged in.
private boolean mDreamsEnabledOnBatteryConfig;
@@ -558,6 +569,9 @@ public final class PowerManagerService extends SystemService
// True if dreams should be activated on dock.
private boolean mDreamsActivateOnDockSetting;
+ /** Whether dreams should be activated when device is postured (stationary and upright) */
+ private boolean mDreamsActivateWhilePosturedSetting;
+
// True if doze should not be started until after the screen off transition.
private boolean mDozeAfterScreenOff;
@@ -1471,6 +1485,9 @@ public final class PowerManagerService extends SystemService
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK),
false, mSettingsObserver, UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED),
+ false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_OFF_TIMEOUT),
false, mSettingsObserver, UserHandle.USER_ALL);
@@ -1549,6 +1566,8 @@ public final class PowerManagerService extends SystemService
com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
mDreamsActivatedOnDockByDefaultConfig = resources.getBoolean(
com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
+ mDreamsActivatedWhilePosturedByDefaultConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_dreamsActivatedOnPosturedByDefault);
mDreamsEnabledOnBatteryConfig = resources.getBoolean(
com.android.internal.R.bool.config_dreamsEnabledOnBattery);
mDreamsBatteryLevelMinimumWhenPoweredConfig = resources.getInteger(
@@ -1589,6 +1608,10 @@ public final class PowerManagerService extends SystemService
Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
mDreamsActivatedOnDockByDefaultConfig ? 1 : 0,
UserHandle.USER_CURRENT) != 0);
+ mDreamsActivateWhilePosturedSetting = (Settings.Secure.getIntForUser(resolver,
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED,
+ mDreamsActivatedWhilePosturedByDefaultConfig ? 1 : 0,
+ UserHandle.USER_CURRENT) != 0);
mScreenOffTimeoutSetting = Settings.System.getIntForUser(resolver,
Settings.System.SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT,
UserHandle.USER_CURRENT);
@@ -3336,7 +3359,7 @@ public final class PowerManagerService extends SystemService
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED
| DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE
| DIRTY_DOCK_STATE | DIRTY_ATTENTIVE | DIRTY_SETTINGS
- | DIRTY_SCREEN_BRIGHTNESS_BOOST)) == 0) {
+ | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_POSTURED_STATE)) == 0) {
return changed;
}
final long time = mClock.uptimeMillis();
@@ -3375,7 +3398,8 @@ public final class PowerManagerService extends SystemService
private boolean shouldNapAtBedTimeLocked() {
return mDreamsActivateOnSleepSetting
|| (mDreamsActivateOnDockSetting
- && mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED);
+ && mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED)
+ || (mDreamsActivateWhilePosturedSetting && mDevicePostured);
}
/**
@@ -4489,6 +4513,17 @@ public final class PowerManagerService extends SystemService
}
}
+ private void setDevicePosturedInternal(boolean isPostured) {
+ if (!allowDreamWhenPostured()) {
+ return;
+ }
+ synchronized (mLock) {
+ mDevicePostured = isPostured;
+ mDirty |= DIRTY_POSTURED_STATE;
+ updatePowerStateLocked();
+ }
+ }
+
private void setUserActivityTimeoutOverrideFromWindowManagerInternal(long timeoutMillis) {
synchronized (mLock) {
if (mUserActivityTimeoutOverrideFromWindowManager != timeoutMillis) {
@@ -4794,6 +4829,8 @@ public final class PowerManagerService extends SystemService
+ mDreamsActivatedOnSleepByDefaultConfig);
pw.println(" mDreamsActivatedOnDockByDefaultConfig="
+ mDreamsActivatedOnDockByDefaultConfig);
+ pw.println(" mDreamsActivatedWhilePosturedByDefaultConfig="
+ + mDreamsActivatedWhilePosturedByDefaultConfig);
pw.println(" mDreamsEnabledOnBatteryConfig="
+ mDreamsEnabledOnBatteryConfig);
pw.println(" mDreamsBatteryLevelMinimumWhenPoweredConfig="
@@ -4805,6 +4842,8 @@ public final class PowerManagerService extends SystemService
pw.println(" mDreamsEnabledSetting=" + mDreamsEnabledSetting);
pw.println(" mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting);
pw.println(" mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting);
+ pw.println(" mDreamsActivateWhilePosturedSetting="
+ + mDreamsActivateWhilePosturedSetting);
pw.println(" mDozeAfterScreenOff=" + mDozeAfterScreenOff);
pw.println(" mBrightWhenDozingConfig=" + mBrightWhenDozingConfig);
pw.println(" mMinimumScreenOffTimeoutConfig=" + mMinimumScreenOffTimeoutConfig);
@@ -7388,6 +7427,11 @@ public final class PowerManagerService extends SystemService
public boolean isAmbientDisplaySuppressed() {
return mAmbientDisplaySuppressionController.isSuppressed();
}
+
+ @Override
+ public void setDevicePostured(boolean isPostured) {
+ setDevicePosturedInternal(isPostured);
+ }
}
/**
diff --git a/services/core/java/com/android/server/power/TEST_MAPPING b/services/core/java/com/android/server/power/TEST_MAPPING
index f67f56db3c1e..c5937e5ffb90 100644
--- a/services/core/java/com/android/server/power/TEST_MAPPING
+++ b/services/core/java/com/android/server/power/TEST_MAPPING
@@ -8,6 +8,12 @@
},
{
"name": "PowerServiceTests_server_power"
+ },
+ {
+ "name": "CtsStatsdAtomHostTestCases_statsdatom_powermanager",
+ "file_patterns": [
+ "(/|^)ThermalManagerService.java"
+ ]
}
],
"postsubmit": [
@@ -22,12 +28,6 @@
},
{
"name": "PowerServiceTests_server_power"
- },
- {
- "name": "CtsStatsdAtomHostTestCases_statsdatom_powermanager",
- "file_patterns": [
- "(/|^)ThermalManagerService.java"
- ]
}
]
}
diff --git a/services/core/java/com/android/server/power/hint/TEST_MAPPING b/services/core/java/com/android/server/power/hint/TEST_MAPPING
index 545070050977..fd81277e9ba4 100644
--- a/services/core/java/com/android/server/power/hint/TEST_MAPPING
+++ b/services/core/java/com/android/server/power/hint/TEST_MAPPING
@@ -15,5 +15,22 @@
{"exclude-annotation": "org.junit.Ignore"}
]
}
+ ],
+ "postsubmit": [
+ {
+ "name": "CtsSystemHealthTestCases",
+ "options": [
+ {"exclude-annotation": "androidx.test.filters.FlakyTest"},
+ {"exclude-annotation": "org.junit.Ignore"}
+ ]
+ },
+ {
+ "name": "CtsOsTestCases",
+ "options": [
+ {"include-filter": "android.os.health.cts.HeadroomTest"},
+ {"exclude-annotation": "androidx.test.filters.FlakyTest"},
+ {"exclude-annotation": "org.junit.Ignore"}
+ ]
+ }
]
} \ No newline at end of file
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 9206cce12cd6..68768b8fa223 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -225,11 +225,19 @@ public class BatteryStatsImpl extends BatteryStats {
@VisibleForTesting
public static final int WAKE_LOCK_WEIGHT = 50;
+ /**
+ * Minimum duration of a battery session. Attempt to automatically start a new
+ * session within this interval are ignored. Explicit resets (e.g. with an adb command) are
+ * not affected by this restriction.
+ */
+ private static final long MIN_BATTERY_SESSION_DURATION_MILLIS = 60000;
+
public static final int RESET_REASON_CORRUPT_FILE = 1;
public static final int RESET_REASON_ADB_COMMAND = 2;
public static final int RESET_REASON_FULL_CHARGE = 3;
public static final int RESET_REASON_ENERGY_CONSUMER_BUCKETS_CHANGE = 4;
public static final int RESET_REASON_PLUGGED_IN_FOR_LONG_DURATION = 5;
+
@NonNull
private final MonotonicClock mMonotonicClock;
@@ -305,6 +313,81 @@ public class BatteryStatsImpl extends BatteryStats {
private final SparseBooleanArray mPowerStatsCollectorEnabled = new SparseBooleanArray();
private boolean mMoveWscLoggingToNotifierEnabled = false;
+ static class BatteryStatsSession {
+ private final BatteryStatsHistory mHistory;
+ private final long mMonotonicStartTime;
+ private final long mStartClockTime;
+ private final long mEstimatedBatteryCapacityMah;
+ private final long mBatteryTimeRemainingMs;
+ private final long mChargeTimeRemainingMs;
+ private final String[] mCustomEnergyConsumerNames;
+ private final BatteryStatsImpl mBatteryStats;
+
+ BatteryStatsSession(BatteryStatsHistory history, long monotonicStartTime,
+ long startClockTime, long batteryTimeRemainingMs, long chargeTimeRemainingMs,
+ long estimatedBatteryCapacityMah, String[] customEnergyConsumerNames,
+ BatteryStatsImpl batteryStats) {
+ mHistory = history;
+ mMonotonicStartTime = monotonicStartTime;
+ mStartClockTime = startClockTime;
+ mEstimatedBatteryCapacityMah = estimatedBatteryCapacityMah;
+ mBatteryTimeRemainingMs = batteryTimeRemainingMs;
+ mChargeTimeRemainingMs = chargeTimeRemainingMs;
+ mCustomEnergyConsumerNames = customEnergyConsumerNames;
+ mBatteryStats = batteryStats;
+ }
+
+ BatteryStatsHistory getHistory() {
+ return mHistory;
+ }
+
+ long getMonotonicStartTime() {
+ return mMonotonicStartTime;
+ }
+
+ long getStartClockTime() {
+ return mStartClockTime;
+ }
+
+ long getBatteryTimeRemainingMs() {
+ return mBatteryTimeRemainingMs;
+ }
+
+ long getChargeTimeRemainingMs() {
+ return mChargeTimeRemainingMs;
+ }
+
+ double getEstimatedBatteryCapacity() {
+ return mEstimatedBatteryCapacityMah;
+ }
+
+ String[] getCustomEnergyConsumerNames() {
+ return mCustomEnergyConsumerNames;
+ }
+
+ /** @deprecated This method will be removed once PowerCalculators are removed from the
+ * code base. */
+ @Deprecated
+ public BatteryStatsImpl getBatteryStats() {
+ return mBatteryStats;
+ }
+ }
+
+ BatteryStatsSession getBatteryStatsSession() {
+ synchronized (this) {
+ long elapsedTimeUs = mClock.elapsedRealtime() * 1000;
+ long batteryTimeRemainingUs = computeBatteryTimeRemaining(elapsedTimeUs);
+ long batteryTimeRemainingMs =
+ batteryTimeRemainingUs >= 0 ? batteryTimeRemainingUs / 1000 : -1;
+ long chargeTimeRemainingUs = computeChargeTimeRemaining(elapsedTimeUs);
+ long chargeTimeRemainingMs =
+ chargeTimeRemainingUs >= 0 ? chargeTimeRemainingUs / 1000 : -1;
+ return new BatteryStatsSession(mHistory, getMonotonicStartTime(), getStartClockTime(),
+ batteryTimeRemainingMs, chargeTimeRemainingMs, getEstimatedBatteryCapacity(),
+ getCustomEnergyConsumerNames(), this);
+ }
+ }
+
private ScreenPowerStatsCollector.ScreenUsageTimeRetriever mScreenUsageTimeRetriever =
new ScreenPowerStatsCollector.ScreenUsageTimeRetriever() {
@@ -554,6 +637,7 @@ public class BatteryStatsImpl extends BatteryStats {
}
private boolean mSaveBatteryUsageStatsOnReset;
+ private boolean mResetBatteryHistoryOnNewSession;
private boolean mAccumulateBatteryUsageStats;
private BatteryUsageStatsProvider mBatteryUsageStatsProvider;
private PowerStatsStore mPowerStatsStore;
@@ -1753,8 +1837,7 @@ public class BatteryStatsImpl extends BatteryStats {
*/
private LongSamplingCounterArray mBinderThreadCpuTimesUs;
- @VisibleForTesting
- protected PowerProfile mPowerProfile;
+ private final PowerProfile mPowerProfile;
@VisibleForTesting
@GuardedBy("this")
@@ -11627,10 +11710,6 @@ public class BatteryStatsImpl extends BatteryStats {
setDisplayCountLocked(mPowerProfile.getNumDisplays());
}
- PowerProfile getPowerProfile() {
- return mPowerProfile;
- }
-
/**
* Starts tracking CPU time-in-state for threads of the system server process,
* keeping a separate account of threads receiving incoming binder calls.
@@ -12074,6 +12153,13 @@ public class BatteryStatsImpl extends BatteryStats {
mAccumulateBatteryUsageStats = accumulateBatteryUsageStats;
}
+ /**
+ * Enables or disables battery history reset at the beginning of a battery stats session.
+ */
+ public void resetBatteryHistoryOnNewSession(boolean enabled) {
+ mResetBatteryHistoryOnNewSession = enabled;
+ }
+
@GuardedBy("this")
public void resetAllStatsAndHistoryLocked(int reason) {
final long mSecUptime = mClock.uptimeMillis();
@@ -12107,11 +12193,29 @@ public class BatteryStatsImpl extends BatteryStats {
initActiveHistoryEventsLocked(mSecRealtime, mSecUptime);
}
+ /**
+ * Starts a new battery stats session, resetting counters and timers. If this method is called
+ * before MIN_BATTERY_SESSION_DURATION_MILLIS from the beginning of the current session, the
+ * call is ignored.
+ */
+ public void startNewSession(int reason) {
+ if (mMonotonicClock.monotonicTime()
+ < mMonotonicStartTime + MIN_BATTERY_SESSION_DURATION_MILLIS) {
+ Slog.i(TAG, "Battery session session duration is too short, ignoring reset request");
+ return;
+ }
+
+ mHandler.post(()-> {
+ saveBatteryUsageStatsOnReset();
+ synchronized (BatteryStatsImpl.this) {
+ resetAllStatsLocked(mClock.uptimeMillis(), mClock.elapsedRealtime(), reason);
+ }
+ });
+ }
+
@GuardedBy("this")
private void resetAllStatsLocked(long uptimeMillis, long elapsedRealtimeMillis,
int resetReason) {
- saveBatteryUsageStatsOnReset(resetReason);
-
final long uptimeUs = uptimeMillis * 1000;
final long elapsedRealtimeUs = elapsedRealtimeMillis * 1000;
mStartCount = 0;
@@ -12250,7 +12354,11 @@ public class BatteryStatsImpl extends BatteryStats {
initDischarge(elapsedRealtimeUs);
- mHistory.reset();
+ if ((resetReason != RESET_REASON_FULL_CHARGE
+ && resetReason != RESET_REASON_PLUGGED_IN_FOR_LONG_DURATION)
+ || mResetBatteryHistoryOnNewSession) {
+ mHistory.reset();
+ }
// Store the empty state to disk to ensure consistency
writeSyncLocked();
@@ -12266,14 +12374,14 @@ public class BatteryStatsImpl extends BatteryStats {
mHandler.sendEmptyMessage(MSG_REPORT_RESET_STATS);
}
- private void saveBatteryUsageStatsOnReset(int resetReason) {
- if (!mSaveBatteryUsageStatsOnReset
- || resetReason == BatteryStatsImpl.RESET_REASON_CORRUPT_FILE) {
+ private void saveBatteryUsageStatsOnReset() {
+ if (!mSaveBatteryUsageStatsOnReset) {
return;
}
if (mAccumulateBatteryUsageStats) {
- mBatteryUsageStatsProvider.accumulateBatteryUsageStats(this);
+ mBatteryUsageStatsProvider.accumulateBatteryUsageStats(getBatteryStatsSession(),
+ mHandler);
} else {
final BatteryUsageStats batteryUsageStats;
synchronized (this) {
@@ -14926,7 +15034,7 @@ public class BatteryStatsImpl extends BatteryStats {
"Resetting due to long plug in duration. elapsed time = " + elapsedRealtimeMs
+ " ms, last plug in time = " + mBatteryPluggedInRealTimeMs
+ " ms, last reset time = " + mRealtimeStartUs / 1000);
- resetAllStatsAndHistoryLocked(RESET_REASON_PLUGGED_IN_FOR_LONG_DURATION);
+ startNewSession(RESET_REASON_PLUGGED_IN_FOR_LONG_DURATION);
}
scheduleNextResetWhilePluggedInCheck();
@@ -15064,7 +15172,7 @@ public class BatteryStatsImpl extends BatteryStats {
});
}
doWrite = true;
- resetAllStatsLocked(mSecUptime, mSecRealtime, RESET_REASON_FULL_CHARGE);
+ startNewSession(RESET_REASON_FULL_CHARGE);
if (chargeUah > 0 && level > 0) {
// Only use the reported coulomb charge value if it is supported and reported.
mEstimatedBatteryCapacityMah = (int) ((chargeUah / 1000) / (level / 100.0));
@@ -15980,6 +16088,8 @@ public class BatteryStatsImpl extends BatteryStats {
if (mEnergyConsumerStatsConfig != null
&& !mEnergyConsumerStatsConfig.isCompatible(config)) {
// Supported power buckets changed since last boot.
+ // Save accumulated battery usage stats before resetting
+ saveBatteryUsageStatsOnReset();
// Existing data is no longer reliable.
resetAllStatsLocked(SystemClock.uptimeMillis(), SystemClock.elapsedRealtime(),
RESET_REASON_ENERGY_CONSUMER_BUCKETS_CHANGE);
@@ -15999,7 +16109,10 @@ public class BatteryStatsImpl extends BatteryStats {
}
} else {
if (mEnergyConsumerStatsConfig != null) {
- // EnergyConsumer no longer supported, wipe out the existing data.
+ // EnergyConsumer no longer supported
+ // Save accumulated battery usage stats before resetting
+ saveBatteryUsageStatsOnReset();
+ // Wipe out the current battery session data.
resetAllStatsLocked(SystemClock.uptimeMillis(), SystemClock.elapsedRealtime(),
RESET_REASON_ENERGY_CONSUMER_BUCKETS_CHANGE);
}
diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
index 8c588b4c9b98..977c6db66106 100644
--- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
+++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
@@ -17,6 +17,7 @@
package com.android.server.power.stats;
import android.annotation.NonNull;
+import android.annotation.UserIdInt;
import android.content.Context;
import android.hardware.SensorManager;
import android.os.BatteryConsumer;
@@ -25,6 +26,8 @@ import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.Handler;
import android.os.Process;
+import android.os.UidBatteryConsumer;
+import android.os.UserHandle;
import android.util.Log;
import android.util.LogWriter;
import android.util.Slog;
@@ -34,6 +37,8 @@ import com.android.internal.os.Clock;
import com.android.internal.os.CpuScalingPolicies;
import com.android.internal.os.MonotonicClock;
import com.android.internal.os.PowerProfile;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.power.stats.BatteryStatsImpl.BatteryStatsSession;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -58,7 +63,6 @@ public class BatteryUsageStatsProvider {
private final MonotonicClock mMonotonicClock;
private final Object mLock = new Object();
private List<PowerCalculator> mPowerCalculators;
- private UserPowerCalculator mUserPowerCalculator;
private long mLastAccumulationMonotonicHistorySize;
private static class AccumulatedBatteryUsageStats {
@@ -81,7 +85,6 @@ public class BatteryUsageStatsProvider {
mAccumulatedBatteryUsageStatsSpanSize = accumulatedBatteryUsageStatsSpanSize;
mClock = clock;
mMonotonicClock = monotonicClock;
- mUserPowerCalculator = new UserPowerCalculator();
mPowerStatsStore.addSectionReader(new BatteryUsageStatsSection.Reader());
mPowerStatsStore.addSectionReader(new AccumulatedBatteryUsageStatsSection.Reader());
@@ -195,22 +198,20 @@ public class BatteryUsageStatsProvider {
mLastAccumulationMonotonicHistorySize = historySize;
}
+ BatteryStatsSession session = stats.getBatteryStatsSession();
+
// No need to store the accumulated stats asynchronously, as the entire accumulation
// operation is async
- handler.post(() -> accumulateBatteryUsageStats(stats, false));
+ handler.post(() -> accumulateBatteryUsageStats(session, handler));
}
/**
* Computes BatteryUsageStats for the period since the last accumulated stats were stored,
- * adds them to the accumulated stats and asynchronously saves the result.
+ * adds them to the accumulated stats and saves the result on the handler thread.
*/
- public void accumulateBatteryUsageStats(BatteryStatsImpl stats) {
- accumulateBatteryUsageStats(stats, true);
- }
-
- private void accumulateBatteryUsageStats(BatteryStatsImpl stats, boolean storeAsync) {
+ public void accumulateBatteryUsageStats(BatteryStatsSession session, Handler handler) {
AccumulatedBatteryUsageStats accumulatedStats = loadAccumulatedBatteryUsageStats();
- updateAccumulatedBatteryUsageStats(accumulatedStats, stats);
+ updateAccumulatedBatteryUsageStats(accumulatedStats, session);
PowerStatsSpan powerStatsSpan = new PowerStatsSpan(AccumulatedBatteryUsageStatsSection.ID);
powerStatsSpan.addSection(
@@ -219,12 +220,12 @@ public class BatteryUsageStatsProvider {
accumulatedStats.startWallClockTime,
accumulatedStats.endMonotonicTime - accumulatedStats.startMonotonicTime);
mMonotonicClock.write();
- if (storeAsync) {
- mPowerStatsStore.storePowerStatsSpanAsync(powerStatsSpan,
- accumulatedStats.builder::discard);
- } else {
+ if (handler.getLooper().isCurrentThread()) {
mPowerStatsStore.storePowerStatsSpan(powerStatsSpan);
accumulatedStats.builder.discard();
+ } else {
+ mPowerStatsStore.storePowerStatsSpanAsync(powerStatsSpan,
+ accumulatedStats.builder::discard);
}
}
@@ -252,9 +253,10 @@ public class BatteryUsageStatsProvider {
synchronized (stats) {
stats.prepareForDumpLocked();
}
+ BatteryStatsSession session = stats.getBatteryStatsSession();
final long currentTimeMillis = mClock.currentTimeMillis();
for (int i = 0; i < queries.size(); i++) {
- results.add(getBatteryUsageStats(stats, queries.get(i), currentTimeMillis));
+ results.add(getBatteryUsageStats(session, queries.get(i), currentTimeMillis));
}
return results;
@@ -265,22 +267,23 @@ public class BatteryUsageStatsProvider {
*/
public BatteryUsageStats getBatteryUsageStats(BatteryStatsImpl stats,
BatteryUsageStatsQuery query) {
- return getBatteryUsageStats(stats, query, mClock.currentTimeMillis());
+ return getBatteryUsageStats(stats.getBatteryStatsSession(), query,
+ mClock.currentTimeMillis());
}
- private BatteryUsageStats getBatteryUsageStats(BatteryStatsImpl stats,
+ private BatteryUsageStats getBatteryUsageStats(BatteryStatsSession session,
BatteryUsageStatsQuery query, long currentTimeMs) {
BatteryUsageStats batteryUsageStats;
if ((query.getFlags()
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_ACCUMULATED) != 0) {
- batteryUsageStats = getAccumulatedBatteryUsageStats(stats, query);
+ batteryUsageStats = getAccumulatedBatteryUsageStats(session, query);
} else if (query.getAggregatedToTimestamp() == 0) {
- BatteryUsageStats.Builder builder = computeBatteryUsageStats(stats, query,
+ BatteryUsageStats.Builder builder = computeBatteryUsageStats(session, query,
query.getMonotonicStartTime(),
query.getMonotonicEndTime(), currentTimeMs);
batteryUsageStats = builder.build();
} else {
- batteryUsageStats = getAggregatedBatteryUsageStats(stats, query);
+ batteryUsageStats = getAggregatedBatteryUsageStats(session, query);
}
if (DEBUG) {
Slog.d(TAG, "query = " + query);
@@ -291,13 +294,13 @@ public class BatteryUsageStatsProvider {
return batteryUsageStats;
}
- private BatteryUsageStats getAccumulatedBatteryUsageStats(BatteryStatsImpl stats,
+ private BatteryUsageStats getAccumulatedBatteryUsageStats(BatteryStatsSession session,
BatteryUsageStatsQuery query) {
AccumulatedBatteryUsageStats accumulatedStats = loadAccumulatedBatteryUsageStats();
if (accumulatedStats.endMonotonicTime == MonotonicClock.UNDEFINED
|| mMonotonicClock.monotonicTime() - accumulatedStats.endMonotonicTime
> query.getMaxStatsAge()) {
- updateAccumulatedBatteryUsageStats(accumulatedStats, stats);
+ updateAccumulatedBatteryUsageStats(accumulatedStats, session);
}
return accumulatedStats.builder.build();
}
@@ -329,19 +332,19 @@ public class BatteryUsageStatsProvider {
}
private void updateAccumulatedBatteryUsageStats(AccumulatedBatteryUsageStats accumulatedStats,
- BatteryStatsImpl stats) {
+ BatteryStatsSession session) {
long startMonotonicTime = accumulatedStats.endMonotonicTime;
if (startMonotonicTime == MonotonicClock.UNDEFINED) {
- startMonotonicTime = stats.getMonotonicStartTime();
+ startMonotonicTime = session.getMonotonicStartTime();
}
long endWallClockTime = mClock.currentTimeMillis();
long endMonotonicTime = mMonotonicClock.monotonicTime();
if (accumulatedStats.builder == null) {
accumulatedStats.builder = new BatteryUsageStats.Builder(
- stats.getCustomEnergyConsumerNames(), true, true, true, 0);
- accumulatedStats.startWallClockTime = stats.getStartClockTime();
- accumulatedStats.startMonotonicTime = stats.getMonotonicStartTime();
+ session.getCustomEnergyConsumerNames(), true, true, true, 0);
+ accumulatedStats.startWallClockTime = session.getStartClockTime();
+ accumulatedStats.startMonotonicTime = session.getMonotonicStartTime();
accumulatedStats.builder.setStatsStartTimestamp(accumulatedStats.startWallClockTime);
}
@@ -350,121 +353,118 @@ public class BatteryUsageStatsProvider {
accumulatedStats.builder.setStatsEndTimestamp(endWallClockTime);
accumulatedStats.builder.setStatsDuration(endWallClockTime - startMonotonicTime);
- mPowerAttributor.estimatePowerConsumption(accumulatedStats.builder, stats.getHistory(),
+ mPowerAttributor.estimatePowerConsumption(accumulatedStats.builder, session.getHistory(),
startMonotonicTime, endMonotonicTime);
- populateGeneralInfo(accumulatedStats.builder, stats);
+ populateBatterySessionInfo(accumulatedStats.builder, session);
}
- private BatteryUsageStats.Builder computeBatteryUsageStats(BatteryStatsImpl stats,
+ private BatteryUsageStats.Builder computeBatteryUsageStats(BatteryStatsSession session,
BatteryUsageStatsQuery query, long monotonicStartTime, long monotonicEndTime,
long currentTimeMs) {
final boolean includeProcessStateData = ((query.getFlags()
- & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA) != 0)
- && stats.isProcessStateDataAvailable();
+ & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA) != 0);
final boolean includeVirtualUids = ((query.getFlags()
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_VIRTUAL_UIDS) != 0);
final double minConsumedPowerThreshold = query.getMinConsumedPowerThreshold();
- String[] customEnergyConsumerNames;
- synchronized (stats) {
- customEnergyConsumerNames = stats.getCustomEnergyConsumerNames();
- }
+ String[] customEnergyConsumerNames = session.getCustomEnergyConsumerNames();
final BatteryUsageStats.Builder batteryUsageStatsBuilder = new BatteryUsageStats.Builder(
customEnergyConsumerNames, includeProcessStateData, query.isScreenStateDataNeeded(),
query.isPowerStateDataNeeded(), minConsumedPowerThreshold);
- synchronized (stats) {
- final List<PowerCalculator> powerCalculators = getPowerCalculators();
- boolean usePowerCalculators = !powerCalculators.isEmpty();
- if (usePowerCalculators
- && (monotonicStartTime != MonotonicClock.UNDEFINED
- || monotonicEndTime != MonotonicClock.UNDEFINED)) {
- Slog.wtfStack(TAG, "BatteryUsageStatsQuery specifies a time "
- + "range that is incompatible with PowerCalculators: "
- + powerCalculators);
- usePowerCalculators = false;
- }
-
- if (monotonicStartTime == MonotonicClock.UNDEFINED) {
- monotonicStartTime = stats.getMonotonicStartTime();
- }
- batteryUsageStatsBuilder.setStatsStartTimestamp(stats.getStartClockTime()
- + (monotonicStartTime - stats.getMonotonicStartTime()));
- if (monotonicEndTime != MonotonicClock.UNDEFINED) {
- batteryUsageStatsBuilder.setStatsEndTimestamp(stats.getStartClockTime()
- + (monotonicEndTime - stats.getMonotonicStartTime()));
- } else {
- batteryUsageStatsBuilder.setStatsEndTimestamp(currentTimeMs);
- }
+ final List<PowerCalculator> powerCalculators = getPowerCalculators();
+ boolean usePowerCalculators = !powerCalculators.isEmpty();
+ if (usePowerCalculators
+ && (monotonicStartTime != MonotonicClock.UNDEFINED
+ || monotonicEndTime != MonotonicClock.UNDEFINED)) {
+ Slog.wtfStack(TAG, "BatteryUsageStatsQuery specifies a time "
+ + "range that is incompatible with PowerCalculators: "
+ + powerCalculators);
+ usePowerCalculators = false;
+ }
- if (usePowerCalculators) {
- final long realtimeUs = mClock.elapsedRealtime() * 1000;
- final long uptimeUs = mClock.uptimeMillis() * 1000;
- final int[] powerComponents = query.getPowerComponents();
- SparseArray<? extends BatteryStats.Uid> uidStats = stats.getUidStats();
- for (int i = uidStats.size() - 1; i >= 0; i--) {
- final BatteryStats.Uid uid = uidStats.valueAt(i);
- if (!includeVirtualUids && uid.getUid() == Process.SDK_SANDBOX_VIRTUAL_UID) {
- continue;
- }
+ if (monotonicStartTime == MonotonicClock.UNDEFINED) {
+ monotonicStartTime = session.getMonotonicStartTime();
+ }
+ batteryUsageStatsBuilder.setStatsStartTimestamp(session.getStartClockTime()
+ + (monotonicStartTime - session.getMonotonicStartTime()));
+ if (monotonicEndTime != MonotonicClock.UNDEFINED) {
+ batteryUsageStatsBuilder.setStatsEndTimestamp(session.getStartClockTime()
+ + (monotonicEndTime - session.getMonotonicStartTime()));
+ } else {
+ batteryUsageStatsBuilder.setStatsEndTimestamp(currentTimeMs);
+ }
- batteryUsageStatsBuilder.getOrCreateUidBatteryConsumerBuilder(uid);
- }
- for (int i = 0, count = powerCalculators.size(); i < count; i++) {
- PowerCalculator powerCalculator = powerCalculators.get(i);
- if (powerComponents != null) {
- boolean include = false;
- for (int powerComponent : powerComponents) {
- if (powerCalculator.isPowerComponentSupported(powerComponent)) {
- include = true;
- break;
- }
- }
- if (!include) {
- continue;
- }
- }
- powerCalculator.calculate(batteryUsageStatsBuilder, stats, realtimeUs, uptimeUs,
- query);
- }
- }
- if ((query.getFlags()
- & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY) != 0) {
- batteryUsageStatsBuilder.setBatteryHistory(stats.copyHistory());
- }
+ if (usePowerCalculators) {
+ BatteryStatsImpl stats = session.getBatteryStats();
+ applyPowerCalculators(batteryUsageStatsBuilder, stats, query, includeVirtualUids);
+ }
+ if ((query.getFlags()
+ & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY) != 0) {
+ batteryUsageStatsBuilder.setBatteryHistory(session.getHistory().copy());
}
- mPowerAttributor.estimatePowerConsumption(batteryUsageStatsBuilder, stats.getHistory(),
+ mPowerAttributor.estimatePowerConsumption(batteryUsageStatsBuilder, session.getHistory(),
monotonicStartTime, monotonicEndTime);
// Combine apps by the user if necessary
- mUserPowerCalculator.calculate(batteryUsageStatsBuilder, stats, 0, 0, query);
+ buildUserBatteryConsumers(batteryUsageStatsBuilder, query.getUserIds());
- populateGeneralInfo(batteryUsageStatsBuilder, stats);
+ populateBatterySessionInfo(batteryUsageStatsBuilder, session);
return batteryUsageStatsBuilder;
}
- private void populateGeneralInfo(BatteryUsageStats.Builder builder, BatteryStatsImpl stats) {
- builder.setBatteryCapacity(stats.getEstimatedBatteryCapacity());
- final long batteryTimeRemainingMs = stats.computeBatteryTimeRemaining(
- mClock.elapsedRealtime() * 1000);
- if (batteryTimeRemainingMs != -1) {
- builder.setBatteryTimeRemainingMs(batteryTimeRemainingMs / 1000);
- }
- final long chargeTimeRemainingMs = stats.computeChargeTimeRemaining(
- mClock.elapsedRealtime() * 1000);
- if (chargeTimeRemainingMs != -1) {
- builder.setChargeTimeRemainingMs(chargeTimeRemainingMs / 1000);
+ private void applyPowerCalculators(BatteryUsageStats.Builder batteryUsageStatsBuilder,
+ BatteryStatsImpl stats, BatteryUsageStatsQuery query,
+ boolean includeVirtualUids) {
+ synchronized (stats) {
+ final List<PowerCalculator> powerCalculators = getPowerCalculators();
+ final long realtimeUs = mClock.elapsedRealtime() * 1000;
+ final long uptimeUs = mClock.uptimeMillis() * 1000;
+ final int[] powerComponents = query.getPowerComponents();
+ SparseArray<? extends BatteryStats.Uid> uidStats = stats.getUidStats();
+ for (int i = uidStats.size() - 1; i >= 0; i--) {
+ final BatteryStats.Uid uid = uidStats.valueAt(i);
+ if (!includeVirtualUids
+ && uid.getUid() == Process.SDK_SANDBOX_VIRTUAL_UID) {
+ continue;
+ }
+
+ batteryUsageStatsBuilder.getOrCreateUidBatteryConsumerBuilder(uid);
+ }
+ for (int i = 0, count = powerCalculators.size(); i < count; i++) {
+ PowerCalculator powerCalculator = powerCalculators.get(i);
+ if (powerComponents != null) {
+ boolean include = false;
+ for (int powerComponent : powerComponents) {
+ if (powerCalculator.isPowerComponentSupported(powerComponent)) {
+ include = true;
+ break;
+ }
+ }
+ if (!include) {
+ continue;
+ }
+ }
+ powerCalculator.calculate(batteryUsageStatsBuilder, stats, realtimeUs, uptimeUs,
+ query);
+ }
}
}
- private BatteryUsageStats getAggregatedBatteryUsageStats(BatteryStatsImpl stats,
+ private void populateBatterySessionInfo(BatteryUsageStats.Builder builder,
+ BatteryStatsSession session) {
+ builder.setBatteryCapacity(session.getEstimatedBatteryCapacity());
+ builder.setBatteryTimeRemainingMs(session.getBatteryTimeRemainingMs());
+ builder.setChargeTimeRemainingMs(session.getChargeTimeRemainingMs());
+ }
+
+ private BatteryUsageStats getAggregatedBatteryUsageStats(BatteryStatsSession stats,
BatteryUsageStatsQuery query) {
final boolean includeProcessStateData = ((query.getFlags()
- & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA) != 0)
- && stats.isProcessStateDataAvailable();
+ & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA) != 0);
final double minConsumedPowerThreshold = query.getMinConsumedPowerThreshold();
final String[] customEnergyConsumerNames = stats.getCustomEnergyConsumerNames();
@@ -539,4 +539,33 @@ public class BatteryUsageStatsProvider {
}
return builder.build();
}
+
+ private void buildUserBatteryConsumers(BatteryUsageStats.Builder builder,
+ @UserIdInt int[] userIds) {
+ if (ArrayUtils.contains(userIds, UserHandle.USER_ALL)) {
+ return;
+ }
+
+ SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
+ builder.getUidBatteryConsumerBuilders();
+
+ for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
+ final UidBatteryConsumer.Builder uidBuilder = uidBatteryConsumerBuilders.valueAt(i);
+ if (uidBuilder.isVirtualUid()) {
+ continue;
+ }
+
+ final int uid = uidBuilder.getUid();
+ if (UserHandle.getAppId(uid) < Process.FIRST_APPLICATION_UID) {
+ continue;
+ }
+
+ final int userId = UserHandle.getUserId(uid);
+ if (!ArrayUtils.contains(userIds, userId)) {
+ uidBuilder.excludeFromBatteryUsageStats();
+ builder.getOrCreateUserBatteryConsumerBuilder(userId)
+ .addUidBatteryConsumer(uidBuilder);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsStore.java b/services/core/java/com/android/server/power/stats/PowerStatsStore.java
index b688d4b3ecde..cdf2f25a109f 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsStore.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsStore.java
@@ -205,21 +205,30 @@ public class PowerStatsStore {
*/
public void storeBatteryUsageStatsAsync(long monotonicStartTime,
BatteryUsageStats batteryUsageStats) {
- mHandler.post(() -> {
+ if (mHandler.getLooper().isCurrentThread()) {
+ storeBatteryUsageStats(monotonicStartTime, batteryUsageStats);
+ } else {
+ mHandler.post(() -> {
+ storeBatteryUsageStats(monotonicStartTime, batteryUsageStats);
+ });
+ }
+ }
+
+ private void storeBatteryUsageStats(long monotonicStartTime,
+ BatteryUsageStats batteryUsageStats) {
+ try {
+ PowerStatsSpan span = new PowerStatsSpan(monotonicStartTime);
+ span.addTimeFrame(monotonicStartTime, batteryUsageStats.getStatsStartTimestamp(),
+ batteryUsageStats.getStatsDuration());
+ span.addSection(new BatteryUsageStatsSection(batteryUsageStats));
+ storePowerStatsSpan(span);
+ } finally {
try {
- PowerStatsSpan span = new PowerStatsSpan(monotonicStartTime);
- span.addTimeFrame(monotonicStartTime, batteryUsageStats.getStatsStartTimestamp(),
- batteryUsageStats.getStatsDuration());
- span.addSection(new BatteryUsageStatsSection(batteryUsageStats));
- storePowerStatsSpan(span);
- } finally {
- try {
- batteryUsageStats.close();
- } catch (IOException e) {
- Slog.e(TAG, "Cannot close BatteryUsageStats", e);
- }
+ batteryUsageStats.close();
+ } catch (IOException e) {
+ Slog.e(TAG, "Cannot close BatteryUsageStats", e);
}
- });
+ }
}
/**
diff --git a/services/core/java/com/android/server/power/stats/UserPowerCalculator.java b/services/core/java/com/android/server/power/stats/UserPowerCalculator.java
deleted file mode 100644
index e08d036f125e..000000000000
--- a/services/core/java/com/android/server/power/stats/UserPowerCalculator.java
+++ /dev/null
@@ -1,70 +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.server.power.stats;
-
-import android.os.BatteryConsumer;
-import android.os.BatteryStats;
-import android.os.BatteryUsageStats;
-import android.os.BatteryUsageStatsQuery;
-import android.os.Process;
-import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
-import android.util.SparseArray;
-
-import com.android.internal.util.ArrayUtils;
-
-/**
- * Computes power consumed by Users
- */
-public class UserPowerCalculator extends PowerCalculator {
-
- @Override
- public boolean isPowerComponentSupported(@BatteryConsumer.PowerComponent int powerComponent) {
- return true;
- }
-
- @Override
- public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
- final int[] userIds = query.getUserIds();
- if (ArrayUtils.contains(userIds, UserHandle.USER_ALL)) {
- return;
- }
-
- SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
- builder.getUidBatteryConsumerBuilders();
-
- for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
- final UidBatteryConsumer.Builder uidBuilder = uidBatteryConsumerBuilders.valueAt(i);
- if (uidBuilder.isVirtualUid()) {
- continue;
- }
-
- final int uid = uidBuilder.getUid();
- if (UserHandle.getAppId(uid) < Process.FIRST_APPLICATION_UID) {
- continue;
- }
-
- final int userId = UserHandle.getUserId(uid);
- if (!ArrayUtils.contains(userIds, userId)) {
- uidBuilder.excludeFromBatteryUsageStats();
- builder.getOrCreateUserBatteryConsumerBuilder(userId)
- .addUidBatteryConsumer(uidBuilder);
- }
- }
- }
-}
diff --git a/services/core/java/com/android/server/security/authenticationpolicy/AuthenticationPolicyService.java b/services/core/java/com/android/server/security/authenticationpolicy/AuthenticationPolicyService.java
index 6798a6146ae0..2452dc59bea5 100644
--- a/services/core/java/com/android/server/security/authenticationpolicy/AuthenticationPolicyService.java
+++ b/services/core/java/com/android/server/security/authenticationpolicy/AuthenticationPolicyService.java
@@ -17,6 +17,7 @@
package com.android.server.security.authenticationpolicy;
import static android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE;
+import static android.security.Flags.disableAdaptiveAuthCounterLock;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
@@ -39,6 +40,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
+import android.provider.Settings;
import android.security.authenticationpolicy.AuthenticationPolicyManager;
import android.security.authenticationpolicy.DisableSecureLockDeviceParams;
import android.security.authenticationpolicy.EnableSecureLockDeviceParams;
@@ -251,6 +253,17 @@ public class AuthenticationPolicyService extends SystemService {
return;
}
+ if (disableAdaptiveAuthCounterLock() && Build.IS_DEBUGGABLE) {
+ final boolean disabled = Settings.Secure.getIntForUser(
+ getContext().getContentResolver(),
+ Settings.Secure.DISABLE_ADAPTIVE_AUTH_LIMIT_LOCK,
+ 0 /* default */, userId) != 0;
+ if (disabled) {
+ Slog.d(TAG, "not locking (disabled by user)");
+ return;
+ }
+ }
+
//TODO: additionally consider the trust signal before locking device
lockDevice(userId);
}
diff --git a/services/core/java/com/android/server/selinux/QuotaExceededException.java b/services/core/java/com/android/server/selinux/QuotaExceededException.java
new file mode 100644
index 000000000000..26d4d827af6b
--- /dev/null
+++ b/services/core/java/com/android/server/selinux/QuotaExceededException.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.
+ */
+package com.android.server.selinux;
+
+/** An exception raised when the quota has been reached.
+ *
+ * This exception is raised in EventLogCollection.add(). See QuotaLimiter
+ * for the implementation details.
+ */
+class QuotaExceededException extends Exception {}
diff --git a/services/core/java/com/android/server/selinux/SelinuxAuditLogsCollector.java b/services/core/java/com/android/server/selinux/SelinuxAuditLogsCollector.java
index 0aa705892376..54365ff03db0 100644
--- a/services/core/java/com/android/server/selinux/SelinuxAuditLogsCollector.java
+++ b/services/core/java/com/android/server/selinux/SelinuxAuditLogsCollector.java
@@ -28,10 +28,8 @@ import com.android.server.utils.Slogf;
import java.io.IOException;
import java.time.Instant;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Queue;
+import java.util.AbstractCollection;
+import java.util.Iterator;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import java.util.regex.Matcher;
@@ -57,6 +55,7 @@ class SelinuxAuditLogsCollector {
private final Supplier<String> mAuditDomainSupplier;
private final RateLimiter mRateLimiter;
private final QuotaLimiter mQuotaLimiter;
+ private EventLogCollection mEventCollection;
@VisibleForTesting Instant mLastWrite = Instant.MIN;
@@ -69,6 +68,7 @@ class SelinuxAuditLogsCollector {
mAuditDomainSupplier = auditDomainSupplier;
mRateLimiter = rateLimiter;
mQuotaLimiter = quotaLimiter;
+ mEventCollection = new EventLogCollection();
}
SelinuxAuditLogsCollector(RateLimiter rateLimiter, QuotaLimiter quotaLimiter) {
@@ -86,75 +86,72 @@ class SelinuxAuditLogsCollector {
mStopRequested.set(stopRequested);
}
- /**
- * Collect and push SELinux audit logs for the provided {@code tagCode}.
+ /** A Collection to work around EventLog.readEvents() constraints.
+ *
+ * This collection only supports add(). Any other method inherited from
+ * Collection will throw an UnsupportedOperationException exception.
*
- * @return true if the job was completed. If the job was interrupted, return false.
+ * This collection ensures that we are processing one event at a time and
+ * avoid collecting all the event objects before processing (e.g.,
+ * ArrayList), which could lead to an OOM situation.
*/
- boolean collect(int tagCode) {
- Queue<Event> logLines = new ArrayDeque<>();
- Instant latestTimestamp = collectLogLines(tagCode, logLines);
-
- boolean quotaExceeded = writeAuditLogs(logLines);
- if (quotaExceeded) {
- Slog.w(TAG, "Too many SELinux logs in the queue, I am giving up.");
- mLastWrite = latestTimestamp; // next run we will ignore all these logs.
- logLines.clear();
+ class EventLogCollection extends AbstractCollection<Event> {
+
+ SelinuxAuditLogBuilder mAuditLogBuilder;
+ int mAuditsWritten = 0;
+ Instant mLatestTimestamp;
+
+ void reset() {
+ mAuditsWritten = 0;
+ mLatestTimestamp = mLastWrite;
+ mAuditLogBuilder = new SelinuxAuditLogBuilder(mAuditDomainSupplier.get());
}
- return logLines.isEmpty();
- }
+ int getAuditsWritten() {
+ return mAuditsWritten;
+ }
- private Instant collectLogLines(int tagCode, Queue<Event> logLines) {
- List<Event> events = new ArrayList<>();
- try {
- EventLog.readEvents(new int[] {tagCode}, events);
- } catch (IOException e) {
- Slog.e(TAG, "Error reading event logs", e);
+ Instant getLatestTimestamp() {
+ return mLatestTimestamp;
}
- Instant latestTimestamp = mLastWrite;
- for (Event event : events) {
- Instant eventTime = Instant.ofEpochSecond(0, event.getTimeNanos());
- if (eventTime.isAfter(latestTimestamp)) {
- latestTimestamp = eventTime;
+ @Override
+ public Iterator<Event> iterator() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int size() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean add(Event event) {
+ if (mStopRequested.get()) {
+ throw new IllegalStateException(new InterruptedException());
}
+
+ Instant eventTime = Instant.ofEpochSecond(/* epochSecond= */ 0, event.getTimeNanos());
if (eventTime.compareTo(mLastWrite) <= 0) {
- continue;
+ return true;
}
Object eventData = event.getData();
if (!(eventData instanceof String)) {
- continue;
+ return true;
}
- logLines.add(event);
- }
- return latestTimestamp;
- }
-
- private boolean writeAuditLogs(Queue<Event> logLines) {
- final SelinuxAuditLogBuilder auditLogBuilder =
- new SelinuxAuditLogBuilder(mAuditDomainSupplier.get());
- int auditsWritten = 0;
-
- while (!mStopRequested.get() && !logLines.isEmpty()) {
- Event event = logLines.poll();
- String logLine = (String) event.getData();
- Instant logTime = Instant.ofEpochSecond(0, event.getTimeNanos());
+ String logLine = (String) eventData;
if (!SELINUX_MATCHER.reset(logLine).matches()) {
- continue;
+ return true;
}
- auditLogBuilder.reset(SELINUX_MATCHER.group("denial"));
- final SelinuxAuditLog auditLog = auditLogBuilder.build();
+ mAuditLogBuilder.reset(SELINUX_MATCHER.group("denial"));
+ final SelinuxAuditLog auditLog = mAuditLogBuilder.build();
if (auditLog == null) {
- continue;
+ return true;
}
if (!mQuotaLimiter.acquire()) {
- if (DEBUG) {
- Slogf.d(TAG, "Running out of quota after %d logs.", auditsWritten);
- }
- return true;
+ throw new IllegalStateException(new QuotaExceededException());
}
mRateLimiter.acquire();
@@ -169,16 +166,50 @@ class SelinuxAuditLogsCollector {
auditLog.mTClass,
auditLog.mPath,
auditLog.mPermissive);
- auditsWritten++;
- if (logTime.isAfter(mLastWrite)) {
- mLastWrite = logTime;
+ mAuditsWritten++;
+ if (eventTime.isAfter(mLatestTimestamp)) {
+ mLatestTimestamp = eventTime;
+ }
+
+ return true;
+ }
+ }
+
+ /**
+ * Collect and push SELinux audit logs for the provided {@code tagCode}.
+ *
+ * @return true if the job was completed. If the job was interrupted or
+ * failed because of IOException, return false.
+ * @throws QuotaExceededException if it ran out of quota.
+ */
+ boolean collect(int tagCode) throws QuotaExceededException {
+ mEventCollection.reset();
+ try {
+ EventLog.readEvents(new int[] {tagCode}, mEventCollection);
+ } catch (IllegalStateException e) {
+ if (e.getCause() instanceof QuotaExceededException) {
+ if (DEBUG) {
+ Slogf.d(TAG, "Running out of quota after %d logs.",
+ mEventCollection.getAuditsWritten());
+ }
+ // next run we will ignore all these logs.
+ mLastWrite = mEventCollection.getLatestTimestamp();
+ throw (QuotaExceededException) e.getCause();
+ } else if (e.getCause() instanceof InterruptedException) {
+ mLastWrite = mEventCollection.getLatestTimestamp();
+ return false;
}
+ throw e;
+ } catch (IOException e) {
+ Slog.e(TAG, "Error reading event logs", e);
+ return false;
}
+ mLastWrite = mEventCollection.getLatestTimestamp();
if (DEBUG) {
- Slogf.d(TAG, "Written %d logs", auditsWritten);
+ Slogf.d(TAG, "Written %d logs", mEventCollection.getAuditsWritten());
}
- return false;
+ return true;
}
}
diff --git a/services/core/java/com/android/server/selinux/SelinuxAuditLogsJob.java b/services/core/java/com/android/server/selinux/SelinuxAuditLogsJob.java
index 0092c3797156..e55e5900f265 100644
--- a/services/core/java/com/android/server/selinux/SelinuxAuditLogsJob.java
+++ b/services/core/java/com/android/server/selinux/SelinuxAuditLogsJob.java
@@ -51,8 +51,12 @@ final class SelinuxAuditLogsJob {
return;
}
mIsRunning.set(true);
- boolean done = mAuditLogsCollector.collect(SelinuxAuditLogsService.AUDITD_TAG_CODE);
- if (done) {
+ try {
+ boolean done = mAuditLogsCollector.collect(SelinuxAuditLogsService.AUDITD_TAG_CODE);
+ if (done) {
+ jobService.jobFinished(params, /* wantsReschedule= */ false);
+ }
+ } catch (QuotaExceededException e) {
jobService.jobFinished(params, /* wantsReschedule= */ false);
}
mIsRunning.set(false);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index a19a3422af06..b7b4cc0b6861 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -95,7 +95,6 @@ import android.view.WindowInsets;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
-import android.view.accessibility.Flags;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -981,16 +980,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
@Override
public void addQsTileToFrontOrEnd(ComponentName tile, boolean end) {
- if (Flags.a11yQsShortcut()) {
- StatusBarManagerService.this.addQsTileToFrontOrEnd(tile, end);
- }
+ StatusBarManagerService.this.addQsTileToFrontOrEnd(tile, end);
}
@Override
public void removeQsTile(ComponentName tile) {
- if (Flags.a11yQsShortcut()) {
- StatusBarManagerService.this.remTile(tile);
- }
+ StatusBarManagerService.this.remTile(tile);
}
};
@@ -1098,19 +1093,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
}
public void addTile(ComponentName component) {
- if (Flags.a11yQsShortcut()) {
- addQsTileToFrontOrEnd(component, false);
- } else {
- enforceStatusBarOrShell();
- enforceValidCallingUser();
-
- if (mBar != null) {
- try {
- mBar.addQsTile(component);
- } catch (RemoteException ex) {
- }
- }
- }
+ addQsTileToFrontOrEnd(component, false);
}
private void addQsTileToFrontOrEnd(ComponentName tile, boolean end) {
diff --git a/services/core/java/com/android/server/timezonedetector/Environment.java b/services/core/java/com/android/server/timezonedetector/Environment.java
new file mode 100644
index 000000000000..795fb02373ff
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/Environment.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.timezonedetector;
+
+import android.annotation.CurrentTimeMillisLong;
+import android.annotation.ElapsedRealtimeLong;
+import android.annotation.NonNull;
+
+import com.android.server.SystemTimeZone;
+
+import java.io.PrintWriter;
+
+/**
+ * Used by the time zone detector code to interact with device state besides that available from
+ * {@link ServiceConfigAccessor}. It can be faked for testing.
+ */
+public interface Environment {
+
+ /**
+ * Returns the device's currently configured time zone. May return an empty string.
+ */
+ @NonNull
+ String getDeviceTimeZone();
+
+ /**
+ * Returns the confidence of the device's current time zone.
+ */
+ @SystemTimeZone.TimeZoneConfidence
+ int getDeviceTimeZoneConfidence();
+
+ /**
+ * Sets the device's time zone, associated confidence, and records a debug log entry.
+ */
+ void setDeviceTimeZoneAndConfidence(
+ @NonNull String zoneId, @SystemTimeZone.TimeZoneConfidence int confidence,
+ @NonNull String logInfo);
+
+ /**
+ * Returns the time according to the elapsed realtime clock, the same as {@link
+ * android.os.SystemClock#elapsedRealtime()}.
+ */
+ @ElapsedRealtimeLong
+ long elapsedRealtimeMillis();
+
+ /**
+ * Returns the current time in milliseconds, the same as
+ * {@link java.lang.System#currentTimeMillis()}.
+ */
+ @CurrentTimeMillisLong
+ long currentTimeMillis();
+
+ /**
+ * Adds a standalone entry to the time zone debug log.
+ */
+ void addDebugLogEntry(@NonNull String logMsg);
+
+ /**
+ * Dumps the time zone debug log to the supplied {@link PrintWriter}.
+ */
+ void dumpDebugLog(PrintWriter printWriter);
+
+ /**
+ * Requests that the supplied runnable be invoked asynchronously.
+ */
+ void runAsync(@NonNull Runnable runnable);
+}
diff --git a/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java b/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
index 449b41a09c51..8491b4818c2e 100644
--- a/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
@@ -16,6 +16,7 @@
package com.android.server.timezonedetector;
+import android.annotation.CurrentTimeMillisLong;
import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
import android.os.Handler;
@@ -31,9 +32,9 @@ import java.io.PrintWriter;
import java.util.Objects;
/**
- * The real implementation of {@link TimeZoneDetectorStrategyImpl.Environment}.
+ * The real implementation of {@link Environment}.
*/
-final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Environment {
+final class EnvironmentImpl implements Environment {
private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
@@ -69,6 +70,11 @@ final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Environment
}
@Override
+ public @CurrentTimeMillisLong long currentTimeMillis() {
+ return System.currentTimeMillis();
+ }
+
+ @Override
public void addDebugLogEntry(@NonNull String logMsg) {
SystemTimeZone.addDebugLogEntry(logMsg);
}
diff --git a/services/core/java/com/android/server/timezonedetector/NotifyingTimeZoneChangeListener.java b/services/core/java/com/android/server/timezonedetector/NotifyingTimeZoneChangeListener.java
index 2e73829ca143..cf85a9a6a706 100644
--- a/services/core/java/com/android/server/timezonedetector/NotifyingTimeZoneChangeListener.java
+++ b/services/core/java/com/android/server/timezonedetector/NotifyingTimeZoneChangeListener.java
@@ -29,6 +29,7 @@ import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.ORIGI
import android.annotation.DurationMillisLong;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
@@ -44,7 +45,6 @@ import android.icu.text.DateFormat;
import android.icu.text.SimpleDateFormat;
import android.icu.util.TimeZone;
import android.os.Handler;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.util.IndentingPrintWriter;
import android.util.Log;
@@ -153,6 +153,9 @@ public class NotifyingTimeZoneChangeListener implements TimeZoneChangeListener {
}
};
+ @NonNull
+ private final Environment mEnvironment;
+
private final Object mConfigurationLock = new Object();
@GuardedBy("mConfigurationLock")
private ConfigurationInternal mConfigurationInternal;
@@ -170,12 +173,14 @@ public class NotifyingTimeZoneChangeListener implements TimeZoneChangeListener {
/** Create and initialise a new {@code TimeZoneChangeTrackerImpl} */
@RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL")
public static NotifyingTimeZoneChangeListener create(Handler handler, Context context,
- ServiceConfigAccessor serviceConfigAccessor) {
+ ServiceConfigAccessor serviceConfigAccessor,
+ @NonNull Environment environment) {
NotifyingTimeZoneChangeListener changeTracker =
new NotifyingTimeZoneChangeListener(handler,
context,
serviceConfigAccessor,
- context.getSystemService(NotificationManager.class));
+ context.getSystemService(NotificationManager.class),
+ environment);
// Pretend there was an update to initialize configuration.
changeTracker.handleConfigurationUpdate();
@@ -184,9 +189,9 @@ public class NotifyingTimeZoneChangeListener implements TimeZoneChangeListener {
}
@VisibleForTesting
- NotifyingTimeZoneChangeListener(
- Handler handler, Context context, ServiceConfigAccessor serviceConfigAccessor,
- NotificationManager notificationManager) {
+ NotifyingTimeZoneChangeListener(Handler handler, Context context,
+ ServiceConfigAccessor serviceConfigAccessor, NotificationManager notificationManager,
+ @NonNull Environment environment) {
mHandler = Objects.requireNonNull(handler);
mContext = Objects.requireNonNull(context);
mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
@@ -194,6 +199,7 @@ public class NotifyingTimeZoneChangeListener implements TimeZoneChangeListener {
this::handleConfigurationUpdate);
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
mNotificationManager = notificationManager;
+ mEnvironment = Objects.requireNonNull(environment);
}
@RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL")
@@ -420,7 +426,7 @@ public class NotifyingTimeZoneChangeListener implements TimeZoneChangeListener {
if (!changeEvent.getOldZoneId().equals(lastChangeEvent.getNewZoneId())) {
int changeEventId = mNextChangeEventId.getAndIncrement();
TimeZoneChangeEvent syntheticChangeEvent = new TimeZoneChangeEvent(
- SystemClock.elapsedRealtime(), System.currentTimeMillis(),
+ mEnvironment.elapsedRealtimeMillis(), mEnvironment.currentTimeMillis(),
ORIGIN_UNKNOWN, UserHandle.USER_NULL, lastChangeEvent.getNewZoneId(),
changeEvent.getOldZoneId(), 0, "Synthetic");
TimeZoneChangeRecord syntheticTrackedChangeEvent =
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
index b2b06b0af5fa..042d81ab6885 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
@@ -25,7 +25,6 @@ import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_S
import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_HIGH;
import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_LOW;
-import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -54,7 +53,6 @@ import com.android.server.SystemTimeZone.TimeZoneConfidence;
import com.android.server.flags.Flags;
import com.android.server.timezonedetector.ConfigurationInternal.DetectionMode;
-import java.io.PrintWriter;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
@@ -67,55 +65,6 @@ import java.util.Objects;
*/
public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrategy {
- /**
- * Used by {@link TimeZoneDetectorStrategyImpl} to interact with device state besides that
- * available from {@link #mServiceConfigAccessor}. It can be faked for testing.
- */
- @VisibleForTesting
- public interface Environment {
-
- /**
- * Returns the device's currently configured time zone. May return an empty string.
- */
- @NonNull
- String getDeviceTimeZone();
-
- /**
- * Returns the confidence of the device's current time zone.
- */
- @TimeZoneConfidence
- int getDeviceTimeZoneConfidence();
-
- /**
- * Sets the device's time zone, associated confidence, and records a debug log entry.
- */
- void setDeviceTimeZoneAndConfidence(
- @NonNull String zoneId, @TimeZoneConfidence int confidence,
- @NonNull String logInfo);
-
- /**
- * Returns the time according to the elapsed realtime clock, the same as {@link
- * android.os.SystemClock#elapsedRealtime()}.
- */
- @ElapsedRealtimeLong
- long elapsedRealtimeMillis();
-
- /**
- * Adds a standalone entry to the time zone debug log.
- */
- void addDebugLogEntry(@NonNull String logMsg);
-
- /**
- * Dumps the time zone debug log to the supplied {@link PrintWriter}.
- */
- void dumpDebugLog(PrintWriter printWriter);
-
- /**
- * Requests that the supplied runnable be invoked asynchronously.
- */
- void runAsync(@NonNull Runnable runnable);
- }
-
private static final String LOG_TAG = TimeZoneDetectorService.TAG;
private static final boolean DBG = TimeZoneDetectorService.DBG;
@@ -263,10 +212,10 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
public static TimeZoneDetectorStrategyImpl create(
@NonNull Context context, @NonNull Handler handler,
@NonNull ServiceConfigAccessor serviceConfigAccessor) {
-
Environment environment = new EnvironmentImpl(handler);
TimeZoneChangeListener changeEventTracker =
- NotifyingTimeZoneChangeListener.create(handler, context, serviceConfigAccessor);
+ NotifyingTimeZoneChangeListener.create(handler, context, serviceConfigAccessor,
+ environment);
return new TimeZoneDetectorStrategyImpl(
serviceConfigAccessor, environment, changeEventTracker);
}
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index ae726c15ed79..a5805043ac42 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -79,6 +79,7 @@ import com.android.internal.app.IBatteryStats;
import com.android.internal.util.DumpUtils;
import com.android.server.SystemService;
import com.android.server.pm.BackgroundUserSoundNotifier;
+import com.android.server.pm.UserManagerService;
import com.android.server.vibrator.VibrationSession.CallerInfo;
import com.android.server.vibrator.VibrationSession.DebugInfo;
import com.android.server.vibrator.VibrationSession.Status;
@@ -200,7 +201,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
VibratorManagerService.this::shouldCancelOnScreenOffLocked,
Status.CANCELLED_BY_SCREEN_OFF);
}
- } else if (android.multiuser.Flags.addUiForSoundsFromBackgroundUsers()
+ } else if (UserManagerService.shouldShowNotificationForBackgroundUserSounds()
&& intent.getAction().equals(BackgroundUserSoundNotifier.ACTION_MUTE_SOUND)) {
synchronized (mLock) {
maybeClearCurrentAndNextSessionsLocked(
@@ -324,7 +325,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
- if (android.multiuser.Flags.addUiForSoundsFromBackgroundUsers()) {
+ if (UserManagerService.shouldShowNotificationForBackgroundUserSounds()) {
filter.addAction(BackgroundUserSoundNotifier.ACTION_MUTE_SOUND);
}
context.registerReceiver(mIntentReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index d31aed2aee37..0226650ec560 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -90,10 +90,6 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VER
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
-import static android.content.pm.ActivityInfo.SIZE_CHANGES_SUPPORTED_METADATA;
-import static android.content.pm.ActivityInfo.SIZE_CHANGES_SUPPORTED_OVERRIDE;
-import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_METADATA;
-import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_OVERRIDE;
import static android.content.res.Configuration.ASSETS_SEQ_UNDEFINED;
import static android.content.res.Configuration.EMPTY;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
@@ -368,6 +364,7 @@ import com.android.internal.content.ReferrerIntent;
import com.android.internal.os.TimeoutRecord;
import com.android.internal.os.TransferPipe;
import com.android.internal.policy.AttributeCache;
+import com.android.internal.policy.PhoneWindow;
import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
@@ -486,6 +483,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final String launchedFromPackage; // always the package who started the activity.
@Nullable
final String launchedFromFeatureId; // always the feature in launchedFromPackage
+ @LaunchSourceType
int mLaunchSourceType; // latest launch source type
final Intent intent; // the original intent that generated us
final String shortComponentName; // the short component name of the intent
@@ -1272,8 +1270,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
pw.println(prefix + "manifestMinAspectRatio="
+ info.getManifestMinAspectRatio());
}
- pw.println(prefix + "supportsSizeChanges="
- + ActivityInfo.sizeChangesSupportModeToString(supportsSizeChanges()));
+ pw.println(
+ prefix + "supportsSizeChanges=" + ActivityInfo.sizeChangesSupportModeToString(
+ mAppCompatController.getSizeCompatModePolicy().supportsSizeChanges()));
if (info.configChanges != 0) {
pw.println(prefix + "configChanges=0x" + Integer.toHexString(info.configChanges));
}
@@ -2027,8 +2026,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|| ent.array.getBoolean(R.styleable.Window_windowShowWallpaper, false);
mStyleFillsParent = mOccludesParent;
mNoDisplay = ent.array.getBoolean(R.styleable.Window_windowNoDisplay, false);
- mOptOutEdgeToEdge = ent.array.getBoolean(
- R.styleable.Window_windowOptOutEdgeToEdgeEnforcement, false);
+ mOptOutEdgeToEdge = PhoneWindow.isOptingOutEdgeToEdgeEnforcement(
+ aInfo.applicationInfo, false /* local */, ent.array);
} else {
mStyleFillsParent = mOccludesParent = true;
mNoDisplay = false;
@@ -2333,6 +2332,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mLaunchSourceType = determineLaunchSourceType(launchFromUid, caller);
}
+ @LaunchSourceType
private int determineLaunchSourceType(int launchFromUid, WindowProcessController caller) {
if (launchFromUid == Process.SYSTEM_UID || launchFromUid == Process.ROOT_UID) {
return LAUNCH_SOURCE_TYPE_SYSTEM;
@@ -3232,7 +3232,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return false;
}
// If the user preference respects aspect ratio, then it becomes non-resizable.
- return mAppCompatController.getAppCompatAspectRatioOverrides()
+ return mAppCompatController.getAspectRatioOverrides()
.userPreferenceCompatibleWithNonResizability();
}
@@ -5477,7 +5477,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
boolean canAffectSystemUiFlags() {
- return task != null && task.canAffectSystemUiFlags() && isVisible()
+ final TaskFragment taskFragment = getTaskFragment();
+ return taskFragment != null && taskFragment.canAffectSystemUiFlags()
+ && isVisible()
&& !mWaitForEnteringPinnedMode && !inPinnedWindowingMode();
}
@@ -6581,7 +6583,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mTaskSupervisor.mStoppingActivities.remove(this);
if (getDisplayArea().allResumedActivitiesComplete()) {
// Construct the compat environment at a relatively stable state if needed.
- mAppCompatController.getAppCompatSizeCompatModePolicy().updateAppCompatDisplayInsets();
+ mAppCompatController.getSizeCompatModePolicy().updateAppCompatDisplayInsets();
mRootWindowContainer.executeAppTransitionForAllDisplay();
}
@@ -8222,7 +8224,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
!= getRequestedConfigurationOrientation(false /*forDisplay */)) {
// Do not change the requested configuration now, because this will be done when setting
// the orientation below with the new mAppCompatDisplayInsets
- mAppCompatController.getAppCompatSizeCompatModePolicy().clearSizeCompatModeAttributes();
+ mAppCompatController.getSizeCompatModePolicy().clearSizeCompatModeAttributes();
}
ProtoLog.v(WM_DEBUG_ORIENTATION,
"Setting requested orientation %s for %s",
@@ -8366,7 +8368,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@Nullable
AppCompatDisplayInsets getAppCompatDisplayInsets() {
- return mAppCompatController.getAppCompatSizeCompatModePolicy().getAppCompatDisplayInsets();
+ return mAppCompatController.getSizeCompatModePolicy().getAppCompatDisplayInsets();
}
/**
@@ -8374,31 +8376,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* density than its parent or its bounds don't fit in parent naturally.
*/
boolean inSizeCompatMode() {
- final AppCompatSizeCompatModePolicy scmPolicy = mAppCompatController
- .getAppCompatSizeCompatModePolicy();
- if (scmPolicy.isInSizeCompatModeForBounds()) {
- return true;
- }
- if (getAppCompatDisplayInsets() == null || !shouldCreateAppCompatDisplayInsets()
- // The orientation is different from parent when transforming.
- || isFixedRotationTransforming()) {
- return false;
- }
- final Rect appBounds = getConfiguration().windowConfiguration.getAppBounds();
- if (appBounds == null) {
- // The app bounds hasn't been computed yet.
- return false;
- }
- final WindowContainer parent = getParent();
- if (parent == null) {
- // The parent of detached Activity can be null.
- return false;
- }
- final Configuration parentConfig = parent.getConfiguration();
- // Although colorMode, screenLayout, smallestScreenWidthDp are also fixed, generally these
- // fields should be changed with density and bounds, so here only compares the most
- // significant field.
- return parentConfig.densityDpi != getConfiguration().densityDpi;
+ return mAppCompatController.getSizeCompatModePolicy().inSizeCompatMode();
}
/**
@@ -8412,67 +8390,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* aspect ratio.
*/
boolean shouldCreateAppCompatDisplayInsets() {
- 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.
- return false;
- }
- switch (supportsSizeChanges()) {
- case SIZE_CHANGES_SUPPORTED_METADATA:
- case SIZE_CHANGES_SUPPORTED_OVERRIDE:
- return false;
- case SIZE_CHANGES_UNSUPPORTED_OVERRIDE:
- return true;
- default:
- // Fall through
- }
- // Use root activity's info for tasks in multi-window mode, or fullscreen tasks in freeform
- // task display areas, to ensure visual consistency across activity launches and exits in
- // the same task.
- final TaskDisplayArea tda = getTaskDisplayArea();
- if (inMultiWindowMode() || (tda != null && tda.inFreeformWindowingMode())) {
- final ActivityRecord root = task != null ? task.getRootActivity() : null;
- if (root != null && root != this && !root.shouldCreateAppCompatDisplayInsets()) {
- // If the root activity doesn't use size compatibility mode, the activities above
- // are forced to be the same for consistent visual appearance.
- return false;
- }
- }
- return !isResizeable() && (info.isFixedOrientation() || hasFixedAspectRatio())
- // The configuration of non-standard type should be enforced by system.
- // {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} is set when this activity is
- // added to a task, but this function is called when resolving the launch params, at
- // which point, the activity type is still undefined if it will be standard.
- // For other non-standard types, the type is set in the constructor, so this should
- // not be a problem.
- && isActivityTypeStandardOrUndefined();
- }
-
- /**
- * Returns whether the activity supports size changes.
- */
- @ActivityInfo.SizeChangesSupportMode
- private int supportsSizeChanges() {
- final AppCompatResizeOverrides resizeOverrides = mAppCompatController.getResizeOverrides();
- if (resizeOverrides.shouldOverrideForceNonResizeApp()) {
- return SIZE_CHANGES_UNSUPPORTED_OVERRIDE;
- }
-
- if (info.supportsSizeChanges) {
- return SIZE_CHANGES_SUPPORTED_METADATA;
- }
-
- if (resizeOverrides.shouldOverrideForceResizeApp()) {
- return SIZE_CHANGES_SUPPORTED_OVERRIDE;
- }
-
- return SIZE_CHANGES_UNSUPPORTED_METADATA;
+ return mAppCompatController.getSizeCompatModePolicy().shouldCreateAppCompatDisplayInsets();
}
@Override
boolean hasSizeCompatBounds() {
- return mAppCompatController.getAppCompatSizeCompatModePolicy().hasSizeCompatBounds();
+ return mAppCompatController.getSizeCompatModePolicy().hasSizeCompatBounds();
}
@Override
@@ -8491,7 +8414,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@Override
float getCompatScale() {
// We need to invoke {#getCompatScale()} only if the CompatScale is not available.
- return mAppCompatController.getAppCompatSizeCompatModePolicy()
+ return mAppCompatController.getSizeCompatModePolicy()
.getCompatScaleIfAvailable(ActivityRecord.super::getCompatScale);
}
@@ -8518,7 +8441,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
newParentConfiguration = mTmpConfig;
}
- mAppCompatController.getAppCompatAspectRatioPolicy().reset();
+ mAppCompatController.getAspectRatioPolicy().reset();
mIsEligibleForFixedOrientationLetterbox = false;
mResolveConfigHint.resolveTmpOverrides(mDisplayContent, newParentConfiguration,
isFixedRotationTransforming());
@@ -8549,15 +8472,15 @@ 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 (!mAppCompatController.getAppCompatAspectRatioPolicy()
+ if (!mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio()
- && !mAppCompatController.getAppCompatAspectRatioOverrides()
+ && !mAppCompatController.getAspectRatioOverrides()
.hasFullscreenOverride()) {
resolveAspectRatioRestriction(newParentConfiguration);
}
final AppCompatDisplayInsets appCompatDisplayInsets = getAppCompatDisplayInsets();
final AppCompatSizeCompatModePolicy scmPolicy =
- mAppCompatController.getAppCompatSizeCompatModePolicy();
+ mAppCompatController.getSizeCompatModePolicy();
if (appCompatDisplayInsets != null) {
scmPolicy.resolveSizeCompatModeConfiguration(newParentConfiguration,
appCompatDisplayInsets, mTmpBounds);
@@ -8586,7 +8509,7 @@ 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.
- && (mAppCompatController.getAppCompatAspectRatioPolicy()
+ && (mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio()
// Limiting check for aspect ratio letterboxing to devices with enabled
// ignoreOrientationRequest. This avoids affecting phones where apps may
@@ -8595,7 +8518,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// accurate on phones shouldn't make the big difference and is expected
// to be already well-tested by apps.
|| (isIgnoreOrientationRequest
- && mAppCompatController.getAppCompatAspectRatioPolicy().isAspectRatioApplied()))) {
+ && mAppCompatController.getAspectRatioPolicy().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 =
@@ -8707,7 +8630,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return mAppCompatController.getTransparentPolicy().getInheritedAppCompatState();
}
final AppCompatSizeCompatModePolicy scmPolicy = mAppCompatController
- .getAppCompatSizeCompatModePolicy();
+ .getSizeCompatModePolicy();
if (scmPolicy.isInSizeCompatModeForBounds()) {
return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
}
@@ -8715,13 +8638,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 (mAppCompatController.getAppCompatAspectRatioPolicy()
- .isLetterboxedForFixedOrientationAndAspectRatio()) {
+ final AppCompatAspectRatioPolicy aspectRatioPolicy =
+ mAppCompatController.getAspectRatioPolicy();
+ if (aspectRatioPolicy.isLetterboxedForFixedOrientationAndAspectRatio()) {
return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION;
}
// Letterbox for limited aspect ratio.
- if (mAppCompatController.getAppCompatAspectRatioPolicy()
- .isLetterboxedForAspectRatioOnly()) {
+ if (aspectRatioPolicy.isLetterboxedForAspectRatioOnly()) {
return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO;
}
@@ -8745,7 +8668,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return;
}
final AppCompatSizeCompatModePolicy scmPolicy =
- mAppCompatController.getAppCompatSizeCompatModePolicy();
+ mAppCompatController.getSizeCompatModePolicy();
final Rect screenResolvedBounds = scmPolicy.replaceResolvedBoundsIfNeeded(resolvedBounds);
final Rect parentAppBounds = mResolveConfigHint.mParentAppBoundsOverride;
final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
@@ -8843,7 +8766,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final Configuration resolvedConfig = getResolvedOverrideConfiguration();
final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
final AppCompatSizeCompatModePolicy scmPolicy =
- mAppCompatController.getAppCompatSizeCompatModePolicy();
+ mAppCompatController.getSizeCompatModePolicy();
return scmPolicy.replaceResolvedBoundsIfNeeded(resolvedBounds);
}
@@ -8997,7 +8920,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
final AppCompatDisplayInsets appCompatDisplayInsets = getAppCompatDisplayInsets();
final AppCompatSizeCompatModePolicy scmPolicy =
- mAppCompatController.getAppCompatSizeCompatModePolicy();
+ mAppCompatController.getSizeCompatModePolicy();
if (appCompatDisplayInsets != null
&& !appCompatDisplayInsets.mIsInFixedOrientationOrAspectRatioLetterbox) {
@@ -9048,8 +8971,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final Rect prevResolvedBounds = new Rect(resolvedBounds);
resolvedBounds.set(containingBounds);
- mAppCompatController.getAppCompatAspectRatioPolicy()
- .applyDesiredAspectRatio(newParentConfig, parentBounds, resolvedBounds,
+ final AppCompatAspectRatioPolicy aspectRatioPolicy = mAppCompatController
+ .getAspectRatioPolicy();
+
+ aspectRatioPolicy.applyDesiredAspectRatio(newParentConfig, parentBounds, resolvedBounds,
containingBoundsWithInsets, containingBounds);
if (appCompatDisplayInsets != null) {
@@ -9078,8 +9003,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// for comparison with size compat app bounds in {@link resolveSizeCompatModeConfiguration}.
mResolveConfigHint.mTmpCompatInsets = appCompatDisplayInsets;
computeConfigByResolveHint(getResolvedOverrideConfiguration(), newParentConfig);
- mAppCompatController.getAppCompatAspectRatioPolicy()
- .setLetterboxBoundsForFixedOrientationAndAspectRatio(new Rect(resolvedBounds));
+ aspectRatioPolicy.setLetterboxBoundsForFixedOrientationAndAspectRatio(
+ new Rect(resolvedBounds));
}
/**
@@ -9096,8 +9021,9 @@ 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();
- mAppCompatController.getAppCompatAspectRatioPolicy()
- .applyAspectRatioForLetterbox(mTmpBounds, parentAppBounds, parentBounds);
+ final AppCompatAspectRatioPolicy aspectRatioPolicy = mAppCompatController
+ .getAspectRatioPolicy();
+ aspectRatioPolicy.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()) {
@@ -9108,8 +9034,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// restrict, the bounds should be the requested override bounds.
mResolveConfigHint.mTmpOverrideDisplayInfo = getFixedRotationTransformDisplayInfo();
computeConfigByResolveHint(resolvedConfig, newParentConfiguration);
- mAppCompatController.getAppCompatAspectRatioPolicy()
- .setLetterboxBoundsForAspectRatio(new Rect(resolvedBounds));
+ aspectRatioPolicy.setLetterboxBoundsForAspectRatio(new Rect(resolvedBounds));
}
}
@@ -9118,7 +9043,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// TODO(b/268458693): Refactor configuration inheritance in case of translucent activities
final Rect superBounds = super.getBounds();
final AppCompatSizeCompatModePolicy scmPolicy =
- mAppCompatController.getAppCompatSizeCompatModePolicy();
+ mAppCompatController.getSizeCompatModePolicy();
return mAppCompatController.getTransparentPolicy().findOpaqueNotFinishingActivityBelow()
.map(ActivityRecord::getBounds)
.orElseGet(() -> scmPolicy.getAppSizeCompatBoundsIfAvailable(superBounds));
@@ -9359,18 +9284,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* Returns the min aspect ratio of this activity.
*/
float getMinAspectRatio() {
- return mAppCompatController.getAppCompatAspectRatioPolicy().getMinAspectRatio();
+ return mAppCompatController.getAspectRatioPolicy().getMinAspectRatio();
}
float getMaxAspectRatio() {
- return mAppCompatController.getAppCompatAspectRatioPolicy().getMaxAspectRatio();
- }
-
- /**
- * Returns true if the activity has maximum or minimum aspect ratio.
- */
- private boolean hasFixedAspectRatio() {
- return getMaxAspectRatio() != 0 || getMinAspectRatio() != 0;
+ return mAppCompatController.getAspectRatioPolicy().getMaxAspectRatio();
}
/**
@@ -9452,7 +9370,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (mVisibleRequested) {
// Calling from here rather than resolveOverrideConfiguration to ensure that this is
// called after full config is updated in ConfigurationContainer#onConfigurationChanged.
- mAppCompatController.getAppCompatSizeCompatModePolicy().updateAppCompatDisplayInsets();
+ mAppCompatController.getSizeCompatModePolicy().updateAppCompatDisplayInsets();
}
// Short circuit: if the two full configurations are equal (the common case), then there is
@@ -9792,7 +9710,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Reset the existing override configuration so it can be updated according to the latest
// configuration.
- mAppCompatController.getAppCompatSizeCompatModePolicy().clearSizeCompatMode();
+ mAppCompatController.getSizeCompatModePolicy().clearSizeCompatMode();
if (!attachedToProcess()) {
return;
@@ -10222,29 +10140,27 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
proto.write(LAST_DROP_INPUT_MODE, mLastDropInputMode);
proto.write(OVERRIDE_ORIENTATION, getOverrideOrientation());
proto.write(SHOULD_SEND_COMPAT_FAKE_FOCUS, shouldSendCompatFakeFocus());
+ final AppCompatCameraOverrides cameraOverrides =
+ mAppCompatController.getAppCompatCameraOverrides();
proto.write(SHOULD_FORCE_ROTATE_FOR_CAMERA_COMPAT,
- mAppCompatController.getAppCompatCameraOverrides()
- .shouldForceRotateForCameraCompat());
+ cameraOverrides.shouldForceRotateForCameraCompat());
proto.write(SHOULD_REFRESH_ACTIVITY_FOR_CAMERA_COMPAT,
- mAppCompatController.getAppCompatCameraOverrides()
- .shouldRefreshActivityForCameraCompat());
+ cameraOverrides.shouldRefreshActivityForCameraCompat());
proto.write(SHOULD_REFRESH_ACTIVITY_VIA_PAUSE_FOR_CAMERA_COMPAT,
- mAppCompatController.getAppCompatCameraOverrides()
- .shouldRefreshActivityViaPauseForCameraCompat());
+ cameraOverrides.shouldRefreshActivityViaPauseForCameraCompat());
+ final AppCompatAspectRatioOverrides aspectRatioOverrides =
+ mAppCompatController.getAspectRatioOverrides();
proto.write(SHOULD_OVERRIDE_MIN_ASPECT_RATIO,
- mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldOverrideMinAspectRatio());
+ aspectRatioOverrides.shouldOverrideMinAspectRatio());
proto.write(SHOULD_IGNORE_ORIENTATION_REQUEST_LOOP,
mAppCompatController.getOrientationOverrides()
.shouldIgnoreOrientationRequestLoop());
proto.write(SHOULD_OVERRIDE_FORCE_RESIZE_APP,
mAppCompatController.getResizeOverrides().shouldOverrideForceResizeApp());
proto.write(SHOULD_ENABLE_USER_ASPECT_RATIO_SETTINGS,
- mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldEnableUserAspectRatioSettings());
+ aspectRatioOverrides.shouldEnableUserAspectRatioSettings());
proto.write(IS_USER_FULLSCREEN_OVERRIDE_ENABLED,
- mAppCompatController.getAppCompatAspectRatioOverrides()
- .isUserFullscreenOverrideEnabled());
+ aspectRatioOverrides.isUserFullscreenOverrideEnabled());
}
@Override
@@ -10473,7 +10389,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* game engines wait to get focus before drawing the content of the app.
*/
boolean shouldSendCompatFakeFocus() {
- return mAppCompatController.getAppCompatFocusOverrides().shouldSendFakeFocus();
+ return mAppCompatController.getFocusOverrides().shouldSendFakeFocus();
}
boolean canCaptureSnapshot() {
diff --git a/services/core/java/com/android/server/wm/ActivitySnapshotController.java b/services/core/java/com/android/server/wm/ActivitySnapshotController.java
index 26b7cc67876e..21628341ea62 100644
--- a/services/core/java/com/android/server/wm/ActivitySnapshotController.java
+++ b/services/core/java/com/android/server/wm/ActivitySnapshotController.java
@@ -100,19 +100,21 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord
ActivitySnapshotController(WindowManagerService service, SnapshotPersistQueue persistQueue) {
super(service);
- mSnapshotPersistQueue = persistQueue;
- mPersistInfoProvider = createPersistInfoProvider(service,
- Environment::getDataSystemCeDirectory);
- mPersister = new TaskSnapshotPersister(persistQueue, mPersistInfoProvider);
- mSnapshotLoader = new AppSnapshotLoader(mPersistInfoProvider);
- initialize(new ActivitySnapshotCache());
-
final boolean snapshotEnabled =
!service.mContext
.getResources()
.getBoolean(com.android.internal.R.bool.config_disableTaskSnapshots)
&& !ActivityManager.isLowRamDeviceStatic(); // Don't support Android Go
setSnapshotEnabled(snapshotEnabled);
+ mSnapshotPersistQueue = persistQueue;
+ mPersistInfoProvider = createPersistInfoProvider(service,
+ Environment::getDataSystemCeDirectory);
+ mPersister = new TaskSnapshotPersister(
+ persistQueue,
+ mPersistInfoProvider,
+ shouldDisableSnapshots());
+ mSnapshotLoader = new AppSnapshotLoader(mPersistInfoProvider);
+ initialize(new ActivitySnapshotCache());
}
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 0ab2ffe3e298..bdbd0d15d982 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1964,7 +1964,6 @@ class ActivityStarter {
if (mLastStartActivityRecord != null) {
targetTaskTop.mLaunchSourceType = mLastStartActivityRecord.mLaunchSourceType;
}
- targetTaskTop.mTransitionController.collect(targetTaskTop);
recordTransientLaunchIfNeeded(targetTaskTop);
// Recycle the target task for this launch.
startResult =
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 9e2c00e6603c..7321f28e4fcd 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -77,7 +77,6 @@ import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_FOCUS;
import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_IMMERSIVE;
import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_LOCKTASK;
import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_TASKS;
-import static com.android.sdksandbox.flags.Flags.sandboxActivitySdkBasedContext;
import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS;
import static com.android.server.am.ActivityManagerServiceDumpActivitiesProto.ROOT_WINDOW_CONTAINER;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.CONFIG_WILL_CHANGE;
@@ -1269,10 +1268,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
static boolean isSdkSandboxActivityIntent(Context context, Intent intent) {
- return intent != null
- && (sandboxActivitySdkBasedContext()
- ? SdkSandboxActivityAuthority.isSdkSandboxActivityIntent(context, intent)
- : intent.isSandboxActivity(context));
+ return SdkSandboxActivityAuthority.isSdkSandboxActivityIntent(context, intent);
}
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 12c8f9ccac7c..906befc1edcc 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -1664,6 +1664,12 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
activityIdleInternal(null /* idleActivity */, false /* fromTimeout */,
true /* processPausingActivities */, null /* configuration */);
+ if (rootTask.getParent() == null) {
+ // The activities in the task may already be finishing. Then the task could be removed
+ // when performing the idle check.
+ return;
+ }
+
// Reparent all the tasks to the bottom of the display
final DisplayContent toDisplay =
mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY);
diff --git a/services/core/java/com/android/server/wm/AppCompatAspectRatioPolicy.java b/services/core/java/com/android/server/wm/AppCompatAspectRatioPolicy.java
index 6a0de98c0ffa..4ecd0bec9880 100644
--- a/services/core/java/com/android/server/wm/AppCompatAspectRatioPolicy.java
+++ b/services/core/java/com/android/server/wm/AppCompatAspectRatioPolicy.java
@@ -76,7 +76,7 @@ class AppCompatAspectRatioPolicy {
private float getDesiredAspectRatio(@NonNull Configuration newParentConfig,
@NonNull Rect parentBounds) {
final float letterboxAspectRatioOverride =
- mAppCompatOverrides.getAppCompatAspectRatioOverrides()
+ mAppCompatOverrides.getAspectRatioOverrides()
.getFixedOrientationLetterboxAspectRatio(newParentConfig);
// Aspect ratio as suggested by the system. Apps requested mix/max aspect ratio will
// be respected in #applyAspectRatio.
@@ -127,7 +127,7 @@ class AppCompatAspectRatioPolicy {
}
final AppCompatAspectRatioOverrides aspectRatioOverrides =
- mAppCompatOverrides.getAppCompatAspectRatioOverrides();
+ mAppCompatOverrides.getAspectRatioOverrides();
if (aspectRatioOverrides.shouldApplyUserMinAspectRatioOverride()) {
return aspectRatioOverrides.getUserMinAspectRatio();
}
@@ -215,6 +215,13 @@ class AppCompatAspectRatioPolicy {
mAppCompatAspectRatioState.mLetterboxBoundsForAspectRatio = bounds;
}
+ /**
+ * Returns true if the activity has maximum or minimum aspect ratio.
+ */
+ boolean hasFixedAspectRatio() {
+ return getMaxAspectRatio() != 0 || getMinAspectRatio() != 0;
+ }
+
private boolean isParentFullscreenPortrait() {
final WindowContainer<?> parent = mActivityRecord.getParent();
return parent != null
diff --git a/services/core/java/com/android/server/wm/AppCompatController.java b/services/core/java/com/android/server/wm/AppCompatController.java
index 6d0e8eacd438..cc9cd90fae06 100644
--- a/services/core/java/com/android/server/wm/AppCompatController.java
+++ b/services/core/java/com/android/server/wm/AppCompatController.java
@@ -31,40 +31,40 @@ class AppCompatController {
@NonNull
private final AppCompatOrientationPolicy mOrientationPolicy;
@NonNull
- private final AppCompatAspectRatioPolicy mAppCompatAspectRatioPolicy;
+ private final AppCompatAspectRatioPolicy mAspectRatioPolicy;
@NonNull
private final AppCompatReachabilityPolicy mReachabilityPolicy;
@NonNull
- private final DesktopAppCompatAspectRatioPolicy mDesktopAppCompatAspectRatioPolicy;
+ private final DesktopAppCompatAspectRatioPolicy mDesktopAspectRatioPolicy;
@NonNull
private final AppCompatOverrides mAppCompatOverrides;
@NonNull
- private final AppCompatDeviceStateQuery mAppCompatDeviceStateQuery;
+ private final AppCompatDeviceStateQuery mDeviceStateQuery;
@NonNull
private final AppCompatLetterboxPolicy mAppCompatLetterboxPolicy;
@NonNull
- private final AppCompatSizeCompatModePolicy mAppCompatSizeCompatModePolicy;
+ private final AppCompatSizeCompatModePolicy mSizeCompatModePolicy;
AppCompatController(@NonNull WindowManagerService wmService,
@NonNull ActivityRecord activityRecord) {
final PackageManager packageManager = wmService.mContext.getPackageManager();
final OptPropFactory optPropBuilder = new OptPropFactory(packageManager,
activityRecord.packageName);
- mAppCompatDeviceStateQuery = new AppCompatDeviceStateQuery(activityRecord);
+ mDeviceStateQuery = new AppCompatDeviceStateQuery(activityRecord);
mTransparentPolicy = new TransparentPolicy(activityRecord,
wmService.mAppCompatConfiguration);
mAppCompatOverrides = new AppCompatOverrides(activityRecord, packageManager,
- wmService.mAppCompatConfiguration, optPropBuilder, mAppCompatDeviceStateQuery);
+ wmService.mAppCompatConfiguration, optPropBuilder, mDeviceStateQuery);
mOrientationPolicy = new AppCompatOrientationPolicy(activityRecord, mAppCompatOverrides);
- mAppCompatAspectRatioPolicy = new AppCompatAspectRatioPolicy(activityRecord,
+ mAspectRatioPolicy = new AppCompatAspectRatioPolicy(activityRecord,
mTransparentPolicy, mAppCompatOverrides);
mReachabilityPolicy = new AppCompatReachabilityPolicy(activityRecord,
wmService.mAppCompatConfiguration);
mAppCompatLetterboxPolicy = new AppCompatLetterboxPolicy(activityRecord,
wmService.mAppCompatConfiguration);
- mDesktopAppCompatAspectRatioPolicy = new DesktopAppCompatAspectRatioPolicy(activityRecord,
+ mDesktopAspectRatioPolicy = new DesktopAppCompatAspectRatioPolicy(activityRecord,
mAppCompatOverrides, mTransparentPolicy, wmService.mAppCompatConfiguration);
- mAppCompatSizeCompatModePolicy = new AppCompatSizeCompatModePolicy(activityRecord,
+ mSizeCompatModePolicy = new AppCompatSizeCompatModePolicy(activityRecord,
mAppCompatOverrides);
}
@@ -79,13 +79,13 @@ class AppCompatController {
}
@NonNull
- AppCompatAspectRatioPolicy getAppCompatAspectRatioPolicy() {
- return mAppCompatAspectRatioPolicy;
+ AppCompatAspectRatioPolicy getAspectRatioPolicy() {
+ return mAspectRatioPolicy;
}
@NonNull
- DesktopAppCompatAspectRatioPolicy getDesktopAppCompatAspectRatioPolicy() {
- return mDesktopAppCompatAspectRatioPolicy;
+ DesktopAppCompatAspectRatioPolicy getDesktopAspectRatioPolicy() {
+ return mDesktopAspectRatioPolicy;
}
@NonNull
@@ -99,8 +99,8 @@ class AppCompatController {
}
@NonNull
- AppCompatAspectRatioOverrides getAppCompatAspectRatioOverrides() {
- return mAppCompatOverrides.getAppCompatAspectRatioOverrides();
+ AppCompatAspectRatioOverrides getAspectRatioOverrides() {
+ return mAppCompatOverrides.getAspectRatioOverrides();
}
@NonNull
@@ -119,8 +119,8 @@ class AppCompatController {
}
@NonNull
- AppCompatFocusOverrides getAppCompatFocusOverrides() {
- return mAppCompatOverrides.getAppCompatFocusOverrides();
+ AppCompatFocusOverrides getFocusOverrides() {
+ return mAppCompatOverrides.getFocusOverrides();
}
@NonNull
@@ -129,8 +129,8 @@ class AppCompatController {
}
@NonNull
- AppCompatDeviceStateQuery getAppCompatDeviceStateQuery() {
- return mAppCompatDeviceStateQuery;
+ AppCompatDeviceStateQuery getDeviceStateQuery() {
+ return mDeviceStateQuery;
}
@NonNull
@@ -139,14 +139,14 @@ class AppCompatController {
}
@NonNull
- AppCompatSizeCompatModePolicy getAppCompatSizeCompatModePolicy() {
- return mAppCompatSizeCompatModePolicy;
+ AppCompatSizeCompatModePolicy getSizeCompatModePolicy() {
+ return mSizeCompatModePolicy;
}
void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
getTransparentPolicy().dump(pw, prefix);
getAppCompatLetterboxPolicy().dump(pw, prefix);
- getAppCompatSizeCompatModePolicy().dump(pw, prefix);
+ getSizeCompatModePolicy().dump(pw, prefix);
}
}
diff --git a/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java b/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java
index af83668f1188..a49bec0ba2f3 100644
--- a/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java
+++ b/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java
@@ -144,7 +144,7 @@ class AppCompatOrientationOverrides {
mOrientationOverridesState.updateOrientationRequestLoopState();
return mOrientationOverridesState.shouldIgnoreRequestInLoop()
- && !mActivityRecord.mAppCompatController.getAppCompatAspectRatioPolicy()
+ && !mActivityRecord.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio();
}
diff --git a/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java b/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java
index fc758ef90995..6202f8070dd4 100644
--- a/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java
+++ b/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java
@@ -55,7 +55,7 @@ class AppCompatOrientationPolicy {
@ActivityInfo.ScreenOrientation
int overrideOrientationIfNeeded(@ActivityInfo.ScreenOrientation int candidate) {
final AppCompatAspectRatioOverrides aspectRatioOverrides =
- mAppCompatOverrides.getAppCompatAspectRatioOverrides();
+ mAppCompatOverrides.getAspectRatioOverrides();
// Ignore all orientation requests of activities for eligible virtual displays.
if (aspectRatioOverrides.shouldIgnoreActivitySizeRestrictionsForDisplay()) {
return SCREEN_ORIENTATION_USER;
diff --git a/services/core/java/com/android/server/wm/AppCompatOverrides.java b/services/core/java/com/android/server/wm/AppCompatOverrides.java
index 9fb54db23d55..2d0ff9be2133 100644
--- a/services/core/java/com/android/server/wm/AppCompatOverrides.java
+++ b/services/core/java/com/android/server/wm/AppCompatOverrides.java
@@ -31,9 +31,9 @@ public class AppCompatOverrides {
@NonNull
private final AppCompatCameraOverrides mAppCompatCameraOverrides;
@NonNull
- private final AppCompatAspectRatioOverrides mAppCompatAspectRatioOverrides;
+ private final AppCompatAspectRatioOverrides mAspectRatioOverrides;
@NonNull
- private final AppCompatFocusOverrides mAppCompatFocusOverrides;
+ private final AppCompatFocusOverrides mFocusOverrides;
@NonNull
private final AppCompatResizeOverrides mResizeOverrides;
@NonNull
@@ -52,11 +52,11 @@ public class AppCompatOverrides {
appCompatConfiguration, optPropBuilder, mAppCompatCameraOverrides);
mReachabilityOverrides = new AppCompatReachabilityOverrides(activityRecord,
appCompatConfiguration, appCompatDeviceStateQuery);
- mAppCompatAspectRatioOverrides = new AppCompatAspectRatioOverrides(activityRecord,
+ mAspectRatioOverrides = new AppCompatAspectRatioOverrides(activityRecord,
appCompatConfiguration, optPropBuilder, appCompatDeviceStateQuery,
mReachabilityOverrides);
- mAppCompatFocusOverrides = new AppCompatFocusOverrides(activityRecord,
- appCompatConfiguration, optPropBuilder);
+ mFocusOverrides = new AppCompatFocusOverrides(activityRecord, appCompatConfiguration,
+ optPropBuilder);
mResizeOverrides = new AppCompatResizeOverrides(activityRecord, packageManager,
optPropBuilder);
mAppCompatLetterboxOverrides = new AppCompatLetterboxOverrides(activityRecord,
@@ -74,13 +74,13 @@ public class AppCompatOverrides {
}
@NonNull
- AppCompatAspectRatioOverrides getAppCompatAspectRatioOverrides() {
- return mAppCompatAspectRatioOverrides;
+ AppCompatAspectRatioOverrides getAspectRatioOverrides() {
+ return mAspectRatioOverrides;
}
@NonNull
- AppCompatFocusOverrides getAppCompatFocusOverrides() {
- return mAppCompatFocusOverrides;
+ AppCompatFocusOverrides getFocusOverrides() {
+ return mFocusOverrides;
}
@NonNull
diff --git a/services/core/java/com/android/server/wm/AppCompatReachabilityPolicy.java b/services/core/java/com/android/server/wm/AppCompatReachabilityPolicy.java
index 087edc184b6f..a7c52bd1fc38 100644
--- a/services/core/java/com/android/server/wm/AppCompatReachabilityPolicy.java
+++ b/services/core/java/com/android/server/wm/AppCompatReachabilityPolicy.java
@@ -107,7 +107,7 @@ class AppCompatReachabilityPolicy {
return;
}
final AppCompatDeviceStateQuery deviceStateQuery = mActivityRecord.mAppCompatController
- .getAppCompatDeviceStateQuery();
+ .getDeviceStateQuery();
final boolean isInFullScreenBookMode = deviceStateQuery
.isDisplayFullScreenAndSeparatingHinge()
&& mAppCompatConfiguration.getIsAutomaticReachabilityInBookModeEnabled();
@@ -153,7 +153,7 @@ class AppCompatReachabilityPolicy {
return;
}
final AppCompatDeviceStateQuery deviceStateQuery = mActivityRecord.mAppCompatController
- .getAppCompatDeviceStateQuery();
+ .getDeviceStateQuery();
final boolean isInFullScreenTabletopMode = deviceStateQuery
.isDisplayFullScreenAndSeparatingHinge();
final int letterboxPositionForVerticalReachability = mAppCompatConfiguration
diff --git a/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java b/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java
index d278dc3d1be7..c6831881ea48 100644
--- a/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java
+++ b/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java
@@ -18,6 +18,10 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.content.pm.ActivityInfo.SIZE_CHANGES_SUPPORTED_METADATA;
+import static android.content.pm.ActivityInfo.SIZE_CHANGES_SUPPORTED_OVERRIDE;
+import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_METADATA;
+import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_OVERRIDE;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
import static com.android.server.wm.DesktopModeHelper.canEnterDesktopMode;
@@ -82,7 +86,8 @@ class AppCompatSizeCompatModePolicy {
}
/**
- * @return The {@code true} if the current instance has {@link #mAppCompatDisplayInsets} without
+ * @return The {@code true} if the current instance has
+ * {@link AppCompatSizeCompatModePolicy#mAppCompatDisplayInsets} without
* considering the inheritance implemented in {@link #getAppCompatDisplayInsets()}
*/
boolean hasAppCompatDisplayInsetsWithoutInheritance() {
@@ -199,7 +204,7 @@ class AppCompatSizeCompatModePolicy {
// 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 AppCompatAspectRatioPolicy aspectRatioPolicy = mActivityRecord.mAppCompatController
- .getAppCompatAspectRatioPolicy();
+ .getAspectRatioPolicy();
final boolean useResolvedBounds = aspectRatioPolicy.isAspectRatioApplied();
final Rect containerBounds = useResolvedBounds
? new Rect(resolvedBounds)
@@ -223,7 +228,10 @@ class AppCompatSizeCompatModePolicy {
int rotation = newParentConfiguration.windowConfiguration.getRotation();
final boolean isFixedToUserRotation = mActivityRecord.mDisplayContent == null
|| mActivityRecord.mDisplayContent.getDisplayRotation().isFixedToUserRotation();
- if (!isFixedToUserRotation && !appCompatDisplayInsets.mIsFloating) {
+ // Ignore parent rotation for floating tasks as window rotation is independent of its parent
+ // and thus will remain, and so should be reconfigured, in its original rotation.
+ if (!isFixedToUserRotation
+ && !newParentConfiguration.windowConfiguration.tasksAreFloating()) {
// Use parent rotation because the original display can be rotated.
resolvedConfig.windowConfiguration.setRotation(rotation);
} else {
@@ -244,8 +252,7 @@ class AppCompatSizeCompatModePolicy {
resolvedBounds.set(containingBounds);
// The size of floating task is fixed (only swap), so the aspect ratio is already correct.
if (!appCompatDisplayInsets.mIsFloating) {
- mActivityRecord.mAppCompatController.getAppCompatAspectRatioPolicy()
- .applyAspectRatioForLetterbox(resolvedBounds, containingAppBounds,
+ aspectRatioPolicy.applyAspectRatioForLetterbox(resolvedBounds, containingAppBounds,
containingBounds);
}
@@ -359,7 +366,7 @@ class AppCompatSizeCompatModePolicy {
}
final Rect letterboxedContainerBounds = mActivityRecord.mAppCompatController
- .getAppCompatAspectRatioPolicy().getLetterboxedContainerBounds();
+ .getAspectRatioPolicy().getLetterboxedContainerBounds();
// The role of AppCompatDisplayInsets is like the override bounds.
mAppCompatDisplayInsets =
@@ -368,6 +375,112 @@ class AppCompatSizeCompatModePolicy {
.mUseOverrideInsetsForConfig);
}
+ /**
+ * @return {@code true} if this activity is in size compatibility mode that uses the different
+ * density than its parent or its bounds don't fit in parent naturally.
+ */
+ boolean inSizeCompatMode() {
+ if (isInSizeCompatModeForBounds()) {
+ return true;
+ }
+ if (getAppCompatDisplayInsets() == null || !shouldCreateAppCompatDisplayInsets()
+ // The orientation is different from parent when transforming.
+ || mActivityRecord.isFixedRotationTransforming()) {
+ return false;
+ }
+ final Rect appBounds = mActivityRecord.getConfiguration().windowConfiguration
+ .getAppBounds();
+ if (appBounds == null) {
+ // The app bounds hasn't been computed yet.
+ return false;
+ }
+ final WindowContainer<?> parent = mActivityRecord.getParent();
+ if (parent == null) {
+ // The parent of detached Activity can be null.
+ return false;
+ }
+ final Configuration parentConfig = parent.getConfiguration();
+ // Although colorMode, screenLayout, smallestScreenWidthDp are also fixed, generally these
+ // fields should be changed with density and bounds, so here only compares the most
+ // significant field.
+ return parentConfig.densityDpi != mActivityRecord.getConfiguration().densityDpi;
+ }
+
+ /**
+ * Indicates the activity will keep the bounds and screen configuration when it was first
+ * launched, no matter how its parent changes.
+ *
+ * <p>If {@true}, then {@link AppCompatDisplayInsets} will be created in {@link
+ * ActivityRecord#resolveOverrideConfiguration} to "freeze" activity bounds and insets.
+ *
+ * @return {@code true} if this activity is declared as non-resizable and fixed orientation or
+ * aspect ratio.
+ */
+ boolean shouldCreateAppCompatDisplayInsets() {
+ if (mActivityRecord.mAppCompatController.getAspectRatioOverrides()
+ .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.
+ return false;
+ }
+ switch (supportsSizeChanges()) {
+ case SIZE_CHANGES_SUPPORTED_METADATA:
+ case SIZE_CHANGES_SUPPORTED_OVERRIDE:
+ return false;
+ case SIZE_CHANGES_UNSUPPORTED_OVERRIDE:
+ return true;
+ default:
+ // Fall through
+ }
+ // Use root activity's info for tasks in multi-window mode, or fullscreen tasks in freeform
+ // task display areas, to ensure visual consistency across activity launches and exits in
+ // the same task.
+ final TaskDisplayArea tda = mActivityRecord.getTaskDisplayArea();
+ if (mActivityRecord.inMultiWindowMode() || (tda != null && tda.inFreeformWindowingMode())) {
+ final Task task = mActivityRecord.getTask();
+ final ActivityRecord root = task != null ? task.getRootActivity() : null;
+ if (root != null && root != mActivityRecord
+ && !root.shouldCreateAppCompatDisplayInsets()) {
+ // If the root activity doesn't use size compatibility mode, the activities above
+ // are forced to be the same for consistent visual appearance.
+ return false;
+ }
+ }
+ final AppCompatAspectRatioPolicy aspectRatioPolicy = mActivityRecord.mAppCompatController
+ .getAspectRatioPolicy();
+ return !mActivityRecord.isResizeable() && (mActivityRecord.info.isFixedOrientation()
+ || aspectRatioPolicy.hasFixedAspectRatio())
+ // The configuration of non-standard type should be enforced by system.
+ // {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} is set when this activity is
+ // added to a task, but this function is called when resolving the launch params, at
+ // which point, the activity type is still undefined if it will be standard.
+ // For other non-standard types, the type is set in the constructor, so this should
+ // not be a problem.
+ && mActivityRecord.isActivityTypeStandardOrUndefined();
+ }
+
+ /**
+ * Returns whether the activity supports size changes.
+ */
+ @ActivityInfo.SizeChangesSupportMode
+ int supportsSizeChanges() {
+ final AppCompatResizeOverrides resizeOverrides = mAppCompatOverrides.getResizeOverrides();
+ if (resizeOverrides.shouldOverrideForceNonResizeApp()) {
+ return SIZE_CHANGES_UNSUPPORTED_OVERRIDE;
+ }
+
+ if (mActivityRecord.info.supportsSizeChanges) {
+ return SIZE_CHANGES_SUPPORTED_METADATA;
+ }
+
+ if (resizeOverrides.shouldOverrideForceResizeApp()) {
+ return SIZE_CHANGES_SUPPORTED_OVERRIDE;
+ }
+
+ return SIZE_CHANGES_UNSUPPORTED_METADATA;
+ }
+
private boolean isInSizeCompatModeForBounds(final @NonNull Rect appBounds,
final @NonNull Rect containerBounds) {
diff --git a/services/core/java/com/android/server/wm/AppCompatUtils.java b/services/core/java/com/android/server/wm/AppCompatUtils.java
index e28dddc496e1..1ab0868b37d1 100644
--- a/services/core/java/com/android/server/wm/AppCompatUtils.java
+++ b/services/core/java/com/android/server/wm/AppCompatUtils.java
@@ -156,7 +156,7 @@ final class AppCompatUtils {
.getAppCompatLetterboxOverrides().isLetterboxEducationEnabled());
final AppCompatAspectRatioOverrides aspectRatioOverrides =
- top.mAppCompatController.getAppCompatAspectRatioOverrides();
+ top.mAppCompatController.getAspectRatioOverrides();
appCompatTaskInfo.setUserFullscreenOverrideEnabled(
aspectRatioOverrides.shouldApplyUserFullscreenOverride());
appCompatTaskInfo.setSystemFullscreenOverrideEnabled(
@@ -206,7 +206,7 @@ final class AppCompatUtils {
appCompatTaskInfo.cameraCompatTaskInfo.freeformCameraCompatMode =
AppCompatCameraPolicy.getCameraCompatFreeformMode(top);
appCompatTaskInfo.setHasMinAspectRatioOverride(top.mAppCompatController
- .getDesktopAppCompatAspectRatioPolicy().hasMinAspectRatioOverride(task));
+ .getDesktopAspectRatioPolicy().hasMinAspectRatioOverride(task));
}
/**
@@ -222,7 +222,7 @@ final class AppCompatUtils {
return "SIZE_COMPAT_MODE";
}
final AppCompatAspectRatioPolicy aspectRatioPolicy = activityRecord.mAppCompatController
- .getAppCompatAspectRatioPolicy();
+ .getAspectRatioPolicy();
if (aspectRatioPolicy.isLetterboxedForFixedOrientationAndAspectRatio()) {
return "FIXED_ORIENTATION";
}
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 37575f00363e..ab32e54b92dd 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -36,6 +36,7 @@ import static com.android.server.wm.BackNavigationProto.SHOW_WALLPAPER;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_PREDICT_BACK;
import static com.android.server.wm.WindowContainer.SYNC_STATE_NONE;
+import android.annotation.BinderThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -44,6 +45,7 @@ import android.content.res.ResourceId;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -705,12 +707,34 @@ class BackNavigationController {
private WindowState mNavigatingWindow;
private RemoteCallback mObserver;
+ private final IBinder.DeathRecipient mListenerDeathRecipient =
+ new IBinder.DeathRecipient() {
+ @Override
+ @BinderThread
+ public void binderDied() {
+ synchronized (mWindowManagerService.mGlobalLock) {
+ stopMonitorForRemote();
+ stopMonitorTransition();
+ }
+ }
+ };
+
void startMonitor(@NonNull WindowState window, @NonNull RemoteCallback observer) {
mNavigatingWindow = window;
mObserver = observer;
+ try {
+ mObserver.getInterface().asBinder().linkToDeath(mListenerDeathRecipient,
+ 0 /* flags */);
+ } catch (RemoteException r) {
+ Slog.e(TAG, "Failed to link to death");
+ }
}
void stopMonitorForRemote() {
+ if (mObserver != null) {
+ mObserver.getInterface().asBinder().unlinkToDeath(mListenerDeathRecipient,
+ 0 /* flags */);
+ }
mObserver = null;
}
diff --git a/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java b/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java
index 43855aa3d247..fee5566af484 100644
--- a/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java
+++ b/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java
@@ -189,7 +189,7 @@ public class DesktopAppCompatAspectRatioPolicy {
final ActivityInfo info = mActivityRecord.info;
final AppCompatAspectRatioOverrides aspectRatioOverrides =
- mAppCompatOverrides.getAppCompatAspectRatioOverrides();
+ mAppCompatOverrides.getAspectRatioOverrides();
if (shouldApplyUserMinAspectRatioOverride(task)) {
return aspectRatioOverrides.getUserMinAspectRatio();
}
@@ -266,7 +266,7 @@ public class DesktopAppCompatAspectRatioPolicy {
return false;
}
- final int userAspectRatioCode = mAppCompatOverrides.getAppCompatAspectRatioOverrides()
+ final int userAspectRatioCode = mAppCompatOverrides.getAspectRatioOverrides()
.getUserMinAspectRatioOverrideCode();
return userAspectRatioCode != USER_MIN_ASPECT_RATIO_UNSET
@@ -281,7 +281,7 @@ public class DesktopAppCompatAspectRatioPolicy {
// 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 mAppCompatOverrides.getAppCompatAspectRatioOverrides()
+ return mAppCompatOverrides.getAspectRatioOverrides()
.getAllowUserAspectRatioOverridePropertyValue()
&& mAppCompatConfiguration.isUserAppAspectRatioSettingsEnabled()
&& task.mDisplayContent.getIgnoreOrientationRequest();
diff --git a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
index fcf88d395f1c..0106a64660fe 100644
--- a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
+++ b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
@@ -104,7 +104,7 @@ public final class DesktopModeBoundsCalculator {
if (!DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()) {
return centerInScreen(idealSize, screenBounds);
}
- if (activity.mAppCompatController.getAppCompatAspectRatioOverrides()
+ if (activity.mAppCompatController.getAspectRatioOverrides()
.hasFullscreenOverride()) {
// If the activity has a fullscreen override applied, it should be treated as
// resizeable and match the device orientation. Thus the ideal size can be
@@ -112,7 +112,7 @@ public final class DesktopModeBoundsCalculator {
return centerInScreen(idealSize, screenBounds);
}
final DesktopAppCompatAspectRatioPolicy desktopAppCompatAspectRatioPolicy =
- activity.mAppCompatController.getDesktopAppCompatAspectRatioPolicy();
+ activity.mAppCompatController.getDesktopAspectRatioPolicy();
float appAspectRatio = desktopAppCompatAspectRatioPolicy.calculateAspectRatio(task);
final float tdaWidth = stableBounds.width();
final float tdaHeight = stableBounds.height();
@@ -190,7 +190,7 @@ public final class DesktopModeBoundsCalculator {
@NonNull ActivityRecord activity, @NonNull Task task) {
final int activityOrientation = activity.getOverrideOrientation();
final DesktopAppCompatAspectRatioPolicy desktopAppCompatAspectRatioPolicy =
- activity.mAppCompatController.getDesktopAppCompatAspectRatioPolicy();
+ activity.mAppCompatController.getDesktopAspectRatioPolicy();
if (desktopAppCompatAspectRatioPolicy.shouldApplyUserMinAspectRatioOverride(task)
&& (!isFixedOrientation(activityOrientation)
|| activityOrientation == SCREEN_ORIENTATION_LOCKED)) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index d32c31f1c1c7..5435d8f164da 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -193,7 +193,6 @@ import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
@@ -2187,12 +2186,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
}
- /** Returns {@code true} if the screen rotation animation needs to wait for the window. */
- boolean shouldSyncRotationChange(WindowState w) {
- final AsyncRotationController controller = mAsyncRotationController;
- return controller == null || !controller.isAsync(w);
- }
-
void notifyInsetsChanged(Consumer<WindowState> dispatchInsetsChanged) {
if (mFixedRotationLaunchingApp != null) {
// The insets state of fixed rotation app is a rotated copy. Make sure the visibilities
@@ -2279,10 +2272,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (!shellTransitions) {
forAllWindows(w -> {
w.seamlesslyRotateIfAllowed(transaction, oldRotation, rotation, rotateSeamlessly);
- if (!rotateSeamlessly && w.mHasSurface) {
- ProtoLog.v(WM_DEBUG_ORIENTATION, "Set mOrientationChanging of %s", w);
- w.setOrientationChanging(true);
- }
}, true /* traverseTopToBottom */);
mPinnedTaskController.startSeamlessRotationIfNeeded(transaction, oldRotation, rotation);
if (!mDisplayRotation.hasSeamlessRotatingWindow()) {
@@ -5083,15 +5072,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
Slog.w(TAG_WM, "Window freeze timeout expired.");
mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
- forAllWindows(w -> {
- if (!w.getOrientationChanging()) {
- return;
- }
- w.orientationChangeTimedOut();
- w.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
- - mWmService.mDisplayFreezeTime);
- Slog.w(TAG_WM, "Force clearing orientation change: " + w);
- }, true /* traverseTopToBottom */);
mWmService.mWindowPlacerLocked.performSurfacePlacement();
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 01e00e9d67f7..999666e22985 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -22,7 +22,6 @@ import static android.view.InsetsFrameProvider.SOURCE_ARBITRARY_RECTANGLE;
import static android.view.InsetsFrameProvider.SOURCE_CONTAINER_BOUNDS;
import static android.view.InsetsFrameProvider.SOURCE_DISPLAY;
import static android.view.InsetsFrameProvider.SOURCE_FRAME;
-import static android.view.ViewRootImpl.CLIENT_IMMERSIVE_CONFIRMATION;
import static android.view.ViewRootImpl.CLIENT_TRANSIENT;
import static android.view.WindowInsetsController.APPEARANCE_FORCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
@@ -193,7 +192,6 @@ public class DisplayPolicy {
private final boolean mCarDockEnablesAccelerometer;
private final boolean mDeskDockEnablesAccelerometer;
private final AccessibilityManager mAccessibilityManager;
- private final ImmersiveModeConfirmation mImmersiveModeConfirmation;
private final ScreenshotHelper mScreenshotHelper;
private final Object mServiceAcquireLock = new Object();
@@ -634,12 +632,6 @@ public class DisplayPolicy {
};
displayContent.mAppTransition.registerListenerLocked(mAppTransitionListener);
displayContent.mTransitionController.registerLegacyListener(mAppTransitionListener);
- if (CLIENT_TRANSIENT || CLIENT_IMMERSIVE_CONFIRMATION) {
- mImmersiveModeConfirmation = null;
- } else {
- mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
- mService.mVrModeEnabled, mCanSystemBarsBeShownByUser);
- }
// TODO: Make it can take screenshot on external display
mScreenshotHelper = displayContent.isDefaultDisplay
@@ -2294,11 +2286,7 @@ public class DisplayPolicy {
}
}
}
- if (CLIENT_IMMERSIVE_CONFIRMATION || CLIENT_TRANSIENT) {
- mStatusBarManagerInternal.confirmImmersivePrompt();
- } else {
- mImmersiveModeConfirmation.confirmCurrentPrompt();
- }
+ mStatusBarManagerInternal.confirmImmersivePrompt();
}
boolean isKeyguardShowing() {
@@ -2523,16 +2511,9 @@ public class DisplayPolicy {
// The immersive confirmation window should be attached to the immersive window root.
final RootDisplayArea root = win.getRootDisplayArea();
final int rootDisplayAreaId = root == null ? FEATURE_UNDEFINED : root.mFeatureId;
- if (!CLIENT_TRANSIENT && !CLIENT_IMMERSIVE_CONFIRMATION) {
- mImmersiveModeConfirmation.immersiveModeChangedLw(rootDisplayAreaId,
- isImmersiveMode,
- mService.mPolicy.isUserSetupComplete(),
- isNavBarEmpty(disableFlags));
- } else {
- // TODO(b/277290737): Move this to the client side, instead of using a proxy.
- callStatusBarSafely(statusBar -> statusBar.immersiveModeChanged(getDisplayId(),
+ // TODO(b/277290737): Move this to the client side, instead of using a proxy.
+ callStatusBarSafely(statusBar -> statusBar.immersiveModeChanged(getDisplayId(),
rootDisplayAreaId, isImmersiveMode));
- }
}
// Show transient bars for panic if needed.
@@ -2745,15 +2726,8 @@ public class DisplayPolicy {
void onPowerKeyDown(boolean isScreenOn) {
// Detect user pressing the power button in panic when an application has
// taken over the whole screen.
- boolean panic = false;
- if (!CLIENT_TRANSIENT && !CLIENT_IMMERSIVE_CONFIRMATION) {
- panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
- SystemClock.elapsedRealtime(), isImmersiveMode(mSystemUiControllingWindow),
- isNavBarEmpty(mLastDisableFlags));
- } else {
- panic = isPowerKeyDownPanic(isScreenOn, SystemClock.elapsedRealtime(),
+ boolean panic = isPowerKeyDownPanic(isScreenOn, SystemClock.elapsedRealtime(),
isImmersiveMode(mSystemUiControllingWindow), isNavBarEmpty(mLastDisableFlags));
- }
if (panic) {
mHandler.post(mHiddenNavPanic);
}
@@ -2774,27 +2748,6 @@ public class DisplayPolicy {
return false;
}
- void onVrStateChangedLw(boolean enabled) {
- if (!CLIENT_TRANSIENT && !CLIENT_IMMERSIVE_CONFIRMATION) {
- mImmersiveModeConfirmation.onVrStateChangedLw(enabled);
- }
- }
-
- /**
- * Called when the state of lock task mode changes. This should be used to disable immersive
- * mode confirmation.
- *
- * @param lockTaskState the new lock task mode state. One of
- * {@link ActivityManager#LOCK_TASK_MODE_NONE},
- * {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
- * {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
- */
- public void onLockTaskStateChangedLw(int lockTaskState) {
- if (!CLIENT_TRANSIENT && !CLIENT_IMMERSIVE_CONFIRMATION) {
- mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState);
- }
- }
-
/** Called when a {@link android.os.PowerManager#USER_ACTIVITY_EVENT_TOUCH} is sent. */
public void onUserActivityEventTouch() {
// If there is keyguard, it may use INPUT_FEATURE_DISABLE_USER_ACTIVITY (InputDispatcher
@@ -2808,14 +2761,6 @@ public class DisplayPolicy {
mService.mAtmService.setProcessAnimatingWhileDozing(w != null ? w.getProcess() : null);
}
- boolean onSystemUiSettingsChanged() {
- if (CLIENT_TRANSIENT || CLIENT_IMMERSIVE_CONFIRMATION) {
- return false;
- } else {
- return mImmersiveModeConfirmation.onSettingChanged(mService.mCurrentUserId);
- }
- }
-
/**
* Request a screenshot be taken.
*
@@ -3025,9 +2970,6 @@ public class DisplayPolicy {
mDisplayContent.mTransitionController.unregisterLegacyListener(mAppTransitionListener);
mHandler.post(mGestureNavigationSettingsObserver::unregister);
mHandler.post(mForceShowNavBarSettingsObserver::unregister);
- if (!CLIENT_TRANSIENT && !CLIENT_IMMERSIVE_CONFIRMATION) {
- mImmersiveModeConfirmation.release();
- }
if (mService.mPointerLocationEnabled) {
setPointerLocationEnabled(false);
}
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index db058cafe5fe..fa748d3a22a5 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -212,7 +212,7 @@ class DragDropController {
surface = null;
mDragState.mPid = callerPid;
mDragState.mUid = callerUid;
- mDragState.mOriginalAlpha = alpha;
+ mDragState.mStartDragAlpha = alpha;
mDragState.mAnimatedScale = callingWin.mGlobalScale;
mDragState.mToken = dragToken;
mDragState.mStartDragDisplayContent = displayContent;
@@ -287,7 +287,7 @@ class DragDropController {
}
final SurfaceControl.Transaction transaction = mDragState.mTransaction;
- transaction.setAlpha(surfaceControl, mDragState.mOriginalAlpha);
+ transaction.setAlpha(surfaceControl, mDragState.mStartDragAlpha);
transaction.show(surfaceControl);
displayContent.reparentToOverlay(transaction, surfaceControl);
mDragState.updateDragSurfaceLocked(true /* keepHandling */,
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index d48b9b4a5d10..69f32cb7b8ea 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -82,6 +82,7 @@ import java.util.concurrent.CompletableFuture;
class DragState {
private static final long MIN_ANIMATION_DURATION_MS = 195;
private static final long MAX_ANIMATION_DURATION_MS = 375;
+ private static final float DIFFERENT_DISPLAY_RETURN_ANIMATION_SCALE = 0.75f;
private static final int DRAG_FLAGS_URI_ACCESS = View.DRAG_FLAG_GLOBAL_URI_READ |
View.DRAG_FLAG_GLOBAL_URI_WRITE;
@@ -114,8 +115,9 @@ class DragState {
boolean mDragResult;
boolean mRelinquishDragSurfaceToDropTarget;
float mAnimatedScale = 1.0f;
- float mOriginalAlpha;
- float mOriginalDisplayX, mOriginalDisplayY;
+ float mStartDragAlpha;
+ // Coords are in display coordinates space.
+ float mStartDragDisplayX, mStartDragDisplayY;
float mCurrentDisplayX, mCurrentDisplayY;
float mThumbOffsetX, mThumbOffsetY;
InputInterceptor mInputInterceptor;
@@ -497,8 +499,8 @@ class DragState {
*/
void broadcastDragStartedLocked(final float touchX, final float touchY) {
Trace.instant(TRACE_TAG_WINDOW_MANAGER, "DragDropController#DRAG_STARTED");
- mOriginalDisplayX = mCurrentDisplayX = touchX;
- mOriginalDisplayY = mCurrentDisplayY = touchY;
+ mStartDragDisplayX = mCurrentDisplayX = touchX;
+ mStartDragDisplayY = mCurrentDisplayY = touchY;
// Cache a base-class instance of the clip metadata so that parceling
// works correctly in calling out to the apps.
@@ -809,21 +811,32 @@ class DragState {
mCurrentDisplayY),
PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, mAnimatedScale,
mAnimatedScale),
- PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, 0f));
+ PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_ALPHA, mStartDragAlpha, 0f));
+ duration = MIN_ANIMATION_DURATION_MS;
+ } else if (Flags.enableConnectedDisplaysDnd() && mCurrentDisplayContent.getDisplayId()
+ != mStartDragDisplayContent.getDisplayId()) {
+ animator = ValueAnimator.ofPropertyValuesHolder(
+ PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_X,
+ mCurrentDisplayX - mThumbOffsetX, mCurrentDisplayX - mThumbOffsetX),
+ PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_Y,
+ mCurrentDisplayY - mThumbOffsetY, mCurrentDisplayY - mThumbOffsetY),
+ PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, mAnimatedScale,
+ DIFFERENT_DISPLAY_RETURN_ANIMATION_SCALE * mAnimatedScale),
+ PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_ALPHA, mStartDragAlpha, 0f));
duration = MIN_ANIMATION_DURATION_MS;
} else {
animator = ValueAnimator.ofPropertyValuesHolder(
PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_X,
- mCurrentDisplayX - mThumbOffsetX, mOriginalDisplayX - mThumbOffsetX),
+ mCurrentDisplayX - mThumbOffsetX, mStartDragDisplayX - mThumbOffsetX),
PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_Y,
- mCurrentDisplayY - mThumbOffsetY, mOriginalDisplayY - mThumbOffsetY),
+ mCurrentDisplayY - mThumbOffsetY, mStartDragDisplayY - mThumbOffsetY),
PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, mAnimatedScale,
mAnimatedScale),
- PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_ALPHA, mOriginalAlpha,
- mOriginalAlpha / 2));
+ PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_ALPHA, mStartDragAlpha,
+ mStartDragAlpha / 2));
- final float translateX = mOriginalDisplayX - mCurrentDisplayX;
- final float translateY = mOriginalDisplayY - mCurrentDisplayY;
+ final float translateX = mStartDragDisplayX - mCurrentDisplayX;
+ final float translateY = mStartDragDisplayY - mCurrentDisplayY;
// Adjust the duration to the travel distance.
final double travelDistance = Math.sqrt(
translateX * translateX + translateY * translateY);
@@ -853,7 +866,7 @@ class DragState {
mCurrentDisplayY),
PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, mAnimatedScale,
mAnimatedScale),
- PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, 0f));
+ PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_ALPHA, mStartDragAlpha, 0f));
} else {
animator = ValueAnimator.ofPropertyValuesHolder(
PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_X,
@@ -861,7 +874,7 @@ class DragState {
PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_Y,
mCurrentDisplayY - mThumbOffsetY, mCurrentDisplayY),
PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, mAnimatedScale, 0),
- PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, 0));
+ PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_ALPHA, mStartDragAlpha, 0));
}
final AnimationListener listener = new AnimationListener();
diff --git a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
index 02a7db19f405..0fbf56d120a8 100644
--- a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
+++ b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
@@ -77,8 +77,9 @@ class EmulatorDisplayOverlay {
mOverlay = context.getDrawable(
com.android.internal.R.drawable.emulator_circular_window_overlay);
- mBlastBufferQueue = new BLASTBufferQueue(TITLE, mSurfaceControl, mScreenSize.x,
- mScreenSize.y, PixelFormat.RGBA_8888);
+ mBlastBufferQueue = new BLASTBufferQueue(TITLE, /* updateDestinationFrame */ true);
+ mBlastBufferQueue.update(mSurfaceControl, mScreenSize.x, mScreenSize.y,
+ PixelFormat.RGBA_8888);
mSurface = mBlastBufferQueue.createSurface();
}
diff --git a/services/core/java/com/android/server/wm/EventLogTags.logtags b/services/core/java/com/android/server/wm/EventLogTags.logtags
index 9d6688648021..5767db1461d0 100644
--- a/services/core/java/com/android/server/wm/EventLogTags.logtags
+++ b/services/core/java/com/android/server/wm/EventLogTags.logtags
@@ -69,7 +69,7 @@ option java_package com.android.server.wm
# bootanim finished:
31007 wm_boot_animation_done (time|2|3)
-# Notify keyguard occlude statuc change to SysUI.
+# Notify keyguard occlude status change to SysUI.
31008 wm_set_keyguard_occluded (occluded|1),(animate|1),(transit|1),(Channel|3)
# Back navigation.
diff --git a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
deleted file mode 100644
index d79c11cecdc0..000000000000
--- a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
+++ /dev/null
@@ -1,533 +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.server.wm;
-
-import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
-import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.ViewRootImpl.CLIENT_TRANSIENT;
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
-import static android.window.DisplayAreaOrganizer.KEY_ROOT_DISPLAY_AREA_ID;
-
-import android.animation.ArgbEvaluator;
-import android.animation.ValueAnimator;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.ActivityThread;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.graphics.Insets;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.util.DisplayMetrics;
-import android.util.Slog;
-import android.view.Display;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.view.WindowInsets;
-import android.view.WindowInsets.Type;
-import android.view.WindowManager;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-import android.widget.Button;
-import android.widget.FrameLayout;
-import android.widget.RelativeLayout;
-
-import com.android.internal.R;
-
-/**
- * Helper to manage showing/hiding a confirmation prompt when the navigation bar is hidden
- * entering immersive mode.
- */
-public class ImmersiveModeConfirmation {
- private static final String TAG = "ImmersiveModeConfirmation";
- private static final boolean DEBUG = false;
- private static final boolean DEBUG_SHOW_EVERY_TIME = false; // super annoying, use with caution
- private static final String CONFIRMED = "confirmed";
- private static final int IMMERSIVE_MODE_CONFIRMATION_WINDOW_TYPE =
- WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
-
- private static boolean sConfirmed;
-
- private final Context mContext;
- private final H mHandler;
- private final long mShowDelayMs;
- private final long mPanicThresholdMs;
- private final IBinder mWindowToken = new Binder();
-
- private ClingWindowView mClingWindow;
- private long mPanicTime;
- /** The last {@link WindowManager} that is used to add the confirmation window. */
- @Nullable
- private WindowManager mWindowManager;
- /**
- * The WindowContext that is registered with {@link #mWindowManager} with options to specify the
- * {@link RootDisplayArea} to attach the confirmation window.
- */
- @Nullable
- private Context mWindowContext;
- /**
- * The root display area feature id that the {@link #mWindowContext} is attaching to.
- */
- private int mWindowContextRootDisplayAreaId = FEATURE_UNDEFINED;
- // Local copy of vr mode enabled state, to avoid calling into VrManager with
- // the lock held.
- private boolean mVrModeEnabled;
- private boolean mCanSystemBarsBeShownByUser;
- private int mLockTaskState = LOCK_TASK_MODE_NONE;
-
- ImmersiveModeConfirmation(Context context, Looper looper, boolean vrModeEnabled,
- boolean canSystemBarsBeShownByUser) {
- final Display display = context.getDisplay();
- final Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();
- mContext = display.getDisplayId() == DEFAULT_DISPLAY
- ? uiContext : uiContext.createDisplayContext(display);
- mHandler = new H(looper);
- mShowDelayMs = context.getResources().getInteger(R.integer.dock_enter_exit_duration) * 3L;
- mPanicThresholdMs = context.getResources()
- .getInteger(R.integer.config_immersive_mode_confirmation_panic);
- mVrModeEnabled = vrModeEnabled;
- mCanSystemBarsBeShownByUser = canSystemBarsBeShownByUser;
- }
-
- static boolean loadSetting(int currentUserId, Context context) {
- final boolean wasConfirmed = sConfirmed;
- sConfirmed = false;
- if (DEBUG) Slog.d(TAG, String.format("loadSetting() currentUserId=%d", currentUserId));
- String value = null;
- try {
- value = Settings.Secure.getStringForUser(context.getContentResolver(),
- Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS,
- UserHandle.USER_CURRENT);
- sConfirmed = CONFIRMED.equals(value);
- if (DEBUG) Slog.d(TAG, "Loaded sConfirmed=" + sConfirmed);
- } catch (Throwable t) {
- Slog.w(TAG, "Error loading confirmations, value=" + value, t);
- }
- return sConfirmed != wasConfirmed;
- }
-
- private static void saveSetting(Context context) {
- if (DEBUG) Slog.d(TAG, "saveSetting()");
- try {
- final String value = sConfirmed ? CONFIRMED : null;
- Settings.Secure.putStringForUser(context.getContentResolver(),
- Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS,
- value,
- UserHandle.USER_CURRENT);
- if (DEBUG) Slog.d(TAG, "Saved value=" + value);
- } catch (Throwable t) {
- Slog.w(TAG, "Error saving confirmations, sConfirmed=" + sConfirmed, t);
- }
- }
-
- void release() {
- mHandler.removeMessages(H.SHOW);
- mHandler.removeMessages(H.HIDE);
- }
-
- boolean onSettingChanged(int currentUserId) {
- final boolean changed = loadSetting(currentUserId, mContext);
- // Remove the window if the setting changes to be confirmed.
- if (changed && sConfirmed) {
- mHandler.sendEmptyMessage(H.HIDE);
- }
- return changed;
- }
-
- void immersiveModeChangedLw(int rootDisplayAreaId, boolean isImmersiveMode,
- boolean userSetupComplete, boolean navBarEmpty) {
- mHandler.removeMessages(H.SHOW);
- if (isImmersiveMode) {
- if (DEBUG) Slog.d(TAG, "immersiveModeChanged() sConfirmed=" + sConfirmed);
- if ((DEBUG_SHOW_EVERY_TIME || !sConfirmed)
- && userSetupComplete
- && !mVrModeEnabled
- && mCanSystemBarsBeShownByUser
- && !navBarEmpty
- && !UserManager.isDeviceInDemoMode(mContext)
- && (mLockTaskState != LOCK_TASK_MODE_LOCKED)) {
- final Message msg = mHandler.obtainMessage(H.SHOW);
- msg.arg1 = rootDisplayAreaId;
- mHandler.sendMessageDelayed(msg, mShowDelayMs);
- }
- } else {
- mHandler.sendEmptyMessage(H.HIDE);
- }
- }
-
- boolean onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode,
- boolean navBarEmpty) {
- if (!isScreenOn && (time - mPanicTime < mPanicThresholdMs)) {
- // turning the screen back on within the panic threshold
- return mClingWindow == null;
- }
- if (isScreenOn && inImmersiveMode && !navBarEmpty) {
- // turning the screen off, remember if we were in immersive mode
- mPanicTime = time;
- } else {
- mPanicTime = 0;
- }
- return false;
- }
-
- void confirmCurrentPrompt() {
- if (mClingWindow != null) {
- if (DEBUG) Slog.d(TAG, "confirmCurrentPrompt()");
- mHandler.post(mConfirm);
- }
- }
-
- private void handleHide() {
- if (mClingWindow != null) {
- if (DEBUG) Slog.d(TAG, "Hiding immersive mode confirmation");
- if (mWindowManager != null) {
- try {
- mWindowManager.removeView(mClingWindow);
- } catch (WindowManager.InvalidDisplayException e) {
- Slog.w(TAG, "Fail to hide the immersive confirmation window because of "
- + e);
- }
- mWindowManager = null;
- mWindowContext = null;
- }
- mClingWindow = null;
- }
- }
-
- private WindowManager.LayoutParams getClingWindowLayoutParams() {
- final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT,
- IMMERSIVE_MODE_CONFIRMATION_WINDOW_TYPE,
- WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
- PixelFormat.TRANSLUCENT);
- lp.setFitInsetsTypes(lp.getFitInsetsTypes() & ~Type.statusBars());
- lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- // Trusted overlay so touches outside the touchable area are allowed to pass through
- lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS
- | WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
- | WindowManager.LayoutParams.PRIVATE_FLAG_IMMERSIVE_CONFIRMATION_WINDOW;
- lp.setTitle("ImmersiveModeConfirmation");
- lp.windowAnimations = com.android.internal.R.style.Animation_ImmersiveModeConfirmation;
- lp.token = getWindowToken();
- return lp;
- }
-
- private FrameLayout.LayoutParams getBubbleLayoutParams() {
- return new FrameLayout.LayoutParams(
- getClingWindowWidth(),
- ViewGroup.LayoutParams.WRAP_CONTENT,
- Gravity.CENTER_HORIZONTAL | Gravity.TOP);
- }
-
- /**
- * Returns the width of the cling window.
- */
- private int getClingWindowWidth() {
- return mContext.getResources().getDimensionPixelSize(
- R.dimen.immersive_mode_cling_width);
- }
-
- /**
- * @return the window token that's used by all ImmersiveModeConfirmation windows.
- */
- IBinder getWindowToken() {
- return mWindowToken;
- }
-
- private class ClingWindowView extends FrameLayout {
- private static final int BGCOLOR = 0x80000000;
- private static final int OFFSET_DP = 96;
- private static final int ANIMATION_DURATION = 250;
-
- private final Runnable mConfirm;
- private final ColorDrawable mColor = new ColorDrawable(0);
- private final Interpolator mInterpolator;
- private ValueAnimator mColorAnim;
- private ViewGroup mClingLayout;
-
- private Runnable mUpdateLayoutRunnable = new Runnable() {
- @Override
- public void run() {
- if (mClingLayout != null && mClingLayout.getParent() != null) {
- mClingLayout.setLayoutParams(getBubbleLayoutParams());
- }
- }
- };
-
- private ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener =
- new ViewTreeObserver.OnComputeInternalInsetsListener() {
- private final int[] mTmpInt2 = new int[2];
-
- @Override
- public void onComputeInternalInsets(
- ViewTreeObserver.InternalInsetsInfo inoutInfo) {
- // Set touchable region to cover the cling layout.
- mClingLayout.getLocationInWindow(mTmpInt2);
- inoutInfo.setTouchableInsets(
- ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
- inoutInfo.touchableRegion.set(
- mTmpInt2[0],
- mTmpInt2[1],
- mTmpInt2[0] + mClingLayout.getWidth(),
- mTmpInt2[1] + mClingLayout.getHeight());
- }
- };
-
- private BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
- post(mUpdateLayoutRunnable);
- }
- }
- };
-
- ClingWindowView(Context context, Runnable confirm) {
- super(context);
- mConfirm = confirm;
- setBackground(mColor);
- setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
- mInterpolator = AnimationUtils
- .loadInterpolator(mContext, android.R.interpolator.linear_out_slow_in);
- }
-
- @Override
- public void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- DisplayMetrics metrics = new DisplayMetrics();
- mContext.getDisplay().getMetrics(metrics);
- float density = metrics.density;
-
- getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsListener);
-
- // create the confirmation cling
- mClingLayout = (ViewGroup)
- View.inflate(getContext(), R.layout.immersive_mode_cling, null);
-
- final Button ok = mClingLayout.findViewById(R.id.ok);
- ok.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mConfirm.run();
- }
- });
- addView(mClingLayout, getBubbleLayoutParams());
-
- if (ActivityManager.isHighEndGfx()) {
- final View cling = mClingLayout;
- cling.setAlpha(0f);
- cling.setTranslationY(-OFFSET_DP * density);
-
- postOnAnimation(new Runnable() {
- @Override
- public void run() {
- cling.animate()
- .alpha(1f)
- .translationY(0)
- .setDuration(ANIMATION_DURATION)
- .setInterpolator(mInterpolator)
- .withLayer()
- .start();
-
- mColorAnim = ValueAnimator.ofObject(new ArgbEvaluator(), 0, BGCOLOR);
- mColorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- final int c = (Integer) animation.getAnimatedValue();
- mColor.setColor(c);
- }
- });
- mColorAnim.setDuration(ANIMATION_DURATION);
- mColorAnim.setInterpolator(mInterpolator);
- mColorAnim.start();
- }
- });
- } else {
- mColor.setColor(BGCOLOR);
- }
-
- mContext.registerReceiver(mReceiver,
- new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
- }
-
- @Override
- public void onDetachedFromWindow() {
- mContext.unregisterReceiver(mReceiver);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent motion) {
- return true;
- }
-
- @Override
- public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- // If the top display cutout overlaps with the full-width (windowWidth=-1)/centered
- // dialog, then adjust the dialog contents by the cutout
- final int width = getWidth();
- final int windowWidth = getClingWindowWidth();
- final Rect topDisplayCutout = insets.getDisplayCutout() != null
- ? insets.getDisplayCutout().getBoundingRectTop()
- : new Rect();
- final boolean intersectsTopCutout = topDisplayCutout.intersects(
- width - (windowWidth / 2), 0,
- width + (windowWidth / 2), topDisplayCutout.bottom);
- if (windowWidth < 0 || (width > 0 && intersectsTopCutout)) {
- final View iconView = findViewById(R.id.immersive_cling_icon);
- RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams)
- iconView.getLayoutParams();
- lp.topMargin = topDisplayCutout.bottom;
- iconView.setLayoutParams(lp);
- }
- // we will be hiding the nav bar, so layout as if it's already hidden
- return new WindowInsets.Builder(insets).setInsets(
- Type.systemBars(), Insets.NONE).build();
- }
- }
-
- /**
- * DO HOLD THE WINDOW MANAGER LOCK WHEN CALLING THIS METHOD
- * The reason why we add this method is to avoid the deadlock of WMG->WMS and WMS->WMG
- * when ImmersiveModeConfirmation object is created.
- *
- * @return the WindowManager specifying with the {@code rootDisplayAreaId} to attach the
- * confirmation window.
- */
- @NonNull
- private WindowManager createWindowManager(int rootDisplayAreaId) {
- if (mWindowManager != null) {
- throw new IllegalStateException(
- "Must not create a new WindowManager while there is an existing one");
- }
- // Create window context to specify the RootDisplayArea
- final Bundle options = getOptionsForWindowContext(rootDisplayAreaId);
- mWindowContextRootDisplayAreaId = rootDisplayAreaId;
- mWindowContext = mContext.createWindowContext(
- IMMERSIVE_MODE_CONFIRMATION_WINDOW_TYPE, options);
- mWindowManager = mWindowContext.getSystemService(WindowManager.class);
- return mWindowManager;
- }
-
- /**
- * Returns options that specify the {@link RootDisplayArea} to attach the confirmation window.
- * {@code null} if the {@code rootDisplayAreaId} is {@link FEATURE_UNDEFINED}.
- */
- @Nullable
- private Bundle getOptionsForWindowContext(int rootDisplayAreaId) {
- // In case we don't care which root display area the window manager is specifying.
- if (rootDisplayAreaId == FEATURE_UNDEFINED) {
- return null;
- }
-
- final Bundle options = new Bundle();
- options.putInt(KEY_ROOT_DISPLAY_AREA_ID, rootDisplayAreaId);
- return options;
- }
-
- private void handleShow(int rootDisplayAreaId) {
- if (mClingWindow != null) {
- if (rootDisplayAreaId == mWindowContextRootDisplayAreaId) {
- if (DEBUG) Slog.d(TAG, "Immersive mode confirmation has already been shown");
- return;
- } else {
- // Hide the existing confirmation before show a new one in the new root.
- if (DEBUG) Slog.d(TAG, "Immersive mode confirmation was shown in a different root");
- handleHide();
- }
- }
-
- if (DEBUG) Slog.d(TAG, "Showing immersive mode confirmation");
- mClingWindow = new ClingWindowView(mContext, mConfirm);
- // show the confirmation
- final WindowManager.LayoutParams lp = getClingWindowLayoutParams();
- try {
- createWindowManager(rootDisplayAreaId).addView(mClingWindow, lp);
- } catch (WindowManager.InvalidDisplayException e) {
- Slog.w(TAG, "Fail to show the immersive confirmation window because of " + e);
- }
- }
-
- private final Runnable mConfirm = new Runnable() {
- @Override
- public void run() {
- if (DEBUG) Slog.d(TAG, "mConfirm.run()");
- if (!sConfirmed) {
- sConfirmed = true;
- saveSetting(mContext);
- }
- handleHide();
- }
- };
-
- private final class H extends Handler {
- private static final int SHOW = 1;
- private static final int HIDE = 2;
-
- H(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (CLIENT_TRANSIENT) {
- return;
- }
- switch(msg.what) {
- case SHOW:
- handleShow(msg.arg1);
- break;
- case HIDE:
- handleHide();
- break;
- }
- }
- }
-
- void onVrStateChangedLw(boolean enabled) {
- mVrModeEnabled = enabled;
- if (mVrModeEnabled) {
- mHandler.removeMessages(H.SHOW);
- mHandler.sendEmptyMessage(H.HIDE);
- }
- }
-
- void onLockTaskModeChangedLw(int lockTaskState) {
- mLockTaskState = lockTaskState;
- }
-}
diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java
index d3c3d2834124..ba1401ab3978 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsController.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsController.java
@@ -79,7 +79,8 @@ class LaunchParamsController {
* @param result The resulting params.
*/
void calculate(Task task, WindowLayout layout, ActivityRecord activity, ActivityRecord source,
- ActivityOptions options, @Nullable Request request, int phase, LaunchParams result) {
+ ActivityOptions options, @Nullable Request request,
+ @LaunchParamsModifier.Phase int phase, LaunchParams result) {
result.reset();
if (task != null || activity != null) {
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index 790858d2eec2..b3eccdbc2452 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -609,7 +609,6 @@ public class LockTaskController {
statusBarService.showPinningEnterExitToast(false /* entering */);
}
}
- mWindowManager.onLockTaskStateChanged(mLockTaskModeState);
} catch (RemoteException ex) {
throw new RuntimeException(ex);
}
@@ -745,7 +744,6 @@ public class LockTaskController {
statusBarService.showPinningEnterExitToast(true /* entering */);
}
}
- mWindowManager.onLockTaskStateChanged(lockTaskModeState);
mLockTaskModeState = lockTaskModeState;
mTaskChangeNotificationController.notifyLockTaskModeChanged(mLockTaskModeState);
setStatusBarState(lockTaskModeState, userId);
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 44f000da3d73..b9550feeab8a 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -40,7 +40,6 @@ import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_TASKS;
-import static com.android.launcher3.Flags.enableUseTopVisibleActivityForExcludeFromRecentTask;
import static com.android.server.wm.ActivityRecord.State.RESUMED;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS_TRIM_TASKS;
@@ -1528,12 +1527,7 @@ class RecentTasks {
}
// The Recents is only supported on default display now, we should only keep the
// most recent task of home display.
- boolean isMostRecentTask;
- if (enableUseTopVisibleActivityForExcludeFromRecentTask()) {
- isMostRecentTask = task.getTopVisibleActivity() != null;
- } else {
- isMostRecentTask = taskIndex == 0;
- }
+ boolean isMostRecentTask = task.getTopVisibleActivity() != null;
return (task.isOnHomeDisplay() && isMostRecentTask);
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 57fe0bb4937e..7a3eb67bf94e 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -152,7 +152,6 @@ import com.android.server.LocalServices;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.AppTimeTracker;
import com.android.server.am.UserState;
-import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.pm.UserManagerInternal;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.policy.WindowManagerPolicy;
@@ -206,7 +205,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// For seamless rotation cases this always stays true, as the windows complete their orientation
// changes 1 by 1 without disturbing global state.
boolean mOrientationChangeComplete = true;
- boolean mWallpaperActionPending = false;
private final Handler mHandler;
@@ -1101,10 +1099,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
}
- if ((bulkUpdateParams & SET_WALLPAPER_ACTION_PENDING) != 0) {
- mWallpaperActionPending = true;
- }
-
return doRequest;
}
@@ -1541,20 +1535,18 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
ActivityInfo aInfo = resolveHomeActivity(userId, homeIntent);
boolean lookForSecondaryHomeActivityInPrimaryHomePackage = aInfo != null;
- if (android.companion.virtual.flags.Flags.vdmCustomHome()) {
- // Resolve the externally set home activity for this display, if any. If it is unset or
- // we fail to resolve it, fallback to the default secondary home activity.
- final ComponentName customHomeComponent =
- taskDisplayArea.getDisplayContent() != null
- ? taskDisplayArea.getDisplayContent().getCustomHomeComponent()
- : null;
- if (customHomeComponent != null) {
- homeIntent.setComponent(customHomeComponent);
- ActivityInfo customHomeActivityInfo = resolveHomeActivity(userId, homeIntent);
- if (customHomeActivityInfo != null) {
- aInfo = customHomeActivityInfo;
- lookForSecondaryHomeActivityInPrimaryHomePackage = false;
- }
+ // Resolve the externally set home activity for this display, if any. If it is unset or
+ // we fail to resolve it, fallback to the default secondary home activity.
+ final ComponentName customHomeComponent =
+ taskDisplayArea.getDisplayContent() != null
+ ? taskDisplayArea.getDisplayContent().getCustomHomeComponent()
+ : null;
+ if (customHomeComponent != null) {
+ homeIntent.setComponent(customHomeComponent);
+ ActivityInfo customHomeActivityInfo = resolveHomeActivity(userId, homeIntent);
+ if (customHomeActivityInfo != null) {
+ aInfo = customHomeActivityInfo;
+ lookForSecondaryHomeActivityInPrimaryHomePackage = false;
}
}
diff --git a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
index 3eb13c52cca6..5e1d7928e96d 100644
--- a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
+++ b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
@@ -231,8 +231,13 @@ class SnapshotPersistQueue {
if (next.isReady(mUserManagerInternal)) {
isReadyToWrite = true;
next.onDequeuedLocked();
- } else {
+ } else if (!mShutdown) {
mWriteQueue.addLast(next);
+ } else {
+ // User manager is locked and device is shutting down, skip writing
+ // this item.
+ next.onDequeuedLocked();
+ next = null;
}
}
}
diff --git a/services/core/java/com/android/server/wm/StrictModeFlash.java b/services/core/java/com/android/server/wm/StrictModeFlash.java
index cdf6b08b1c57..b6365ad47535 100644
--- a/services/core/java/com/android/server/wm/StrictModeFlash.java
+++ b/services/core/java/com/android/server/wm/StrictModeFlash.java
@@ -63,8 +63,9 @@ class StrictModeFlash {
mSurfaceControl = ctrl;
mDrawNeeded = true;
- mBlastBufferQueue = new BLASTBufferQueue(TITLE, mSurfaceControl, 1 /* width */,
- 1 /* height */, PixelFormat.RGBA_8888);
+ mBlastBufferQueue = new BLASTBufferQueue(TITLE, /* updateDestinationFrame */ true);
+ mBlastBufferQueue.update(mSurfaceControl, 1 /* width */, 1 /* height */,
+ PixelFormat.RGBA_8888);
mSurface = mBlastBufferQueue.createSurface();
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index fe478c60bc32..295759c2fc7e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -468,9 +468,6 @@ class Task extends TaskFragment {
// NOTE: This value needs to be persisted with each task
private TaskDescription mTaskDescription;
- /** @see #setCanAffectSystemUiFlags */
- private boolean mCanAffectSystemUiFlags = true;
-
private static Exception sTmpException;
private boolean mForceShowForAllUsers;
@@ -3288,21 +3285,6 @@ class Task extends TaskFragment {
return isRootTask() && callback.test(this) ? this : null;
}
- /**
- * @param canAffectSystemUiFlags If false, all windows in this task can not affect SystemUI
- * flags. See {@link WindowState#canAffectSystemUiFlags()}.
- */
- void setCanAffectSystemUiFlags(boolean canAffectSystemUiFlags) {
- mCanAffectSystemUiFlags = canAffectSystemUiFlags;
- }
-
- /**
- * @see #setCanAffectSystemUiFlags
- */
- boolean canAffectSystemUiFlags() {
- return mCanAffectSystemUiFlags;
- }
-
void dontAnimateDimExit() {
mDimmer.dontAnimateExit();
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index a031acad638f..1993053c16cd 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -409,6 +409,9 @@ class TaskFragment extends WindowContainer<WindowContainer> {
private boolean mForceTranslucent = false;
+ /** @see #setCanAffectSystemUiFlags */
+ private boolean mCanAffectSystemUiFlags = true;
+
final Point mLastSurfaceSize = new Point();
private final Rect mTmpBounds = new Rect();
@@ -967,6 +970,27 @@ class TaskFragment extends WindowContainer<WindowContainer> {
}
/**
+ * @param canAffectSystemUiFlags If false, all windows in this taskfragment can not affect
+ * SystemUI flags. See
+ * {@link WindowState#canAffectSystemUiFlags()}.
+ */
+ void setCanAffectSystemUiFlags(boolean canAffectSystemUiFlags) {
+ mCanAffectSystemUiFlags = canAffectSystemUiFlags;
+ }
+
+ /**
+ * @see #setCanAffectSystemUiFlags
+ */
+ boolean canAffectSystemUiFlags() {
+ if (!mCanAffectSystemUiFlags) {
+ return false;
+ }
+ final TaskFragment parentTaskFragment =
+ getParent() != null ? getParent().asTaskFragment() : null;
+ return parentTaskFragment == null || parentTaskFragment.canAffectSystemUiFlags();
+ }
+
+ /**
* Returns the TaskFragment that is being organized, which could be this or the ascendant
* TaskFragment.
*/
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index c39671d76929..e3a5b66b83fd 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -96,9 +96,10 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
}
@Override
+ @Result
public int onCalculate(@Nullable Task task, @Nullable ActivityInfo.WindowLayout layout,
@Nullable ActivityRecord activity, @Nullable ActivityRecord source,
- @Nullable ActivityOptions options, @Nullable Request request, int phase,
+ @Nullable ActivityOptions options, @Nullable Request request, @Phase int phase,
LaunchParams currentParams, LaunchParams outParams) {
initLogBuilder(task, activity);
final int result = calculate(task, layout, activity, source, options, request, phase,
@@ -107,9 +108,10 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
return result;
}
+ @Result
private int calculate(@Nullable Task task, @Nullable ActivityInfo.WindowLayout layout,
@Nullable ActivityRecord activity, @Nullable ActivityRecord source,
- @Nullable ActivityOptions options, @Nullable Request request, int phase,
+ @Nullable ActivityOptions options, @Nullable Request request, @Phase int phase,
LaunchParams currentParams, LaunchParams outParams) {
final ActivityRecord root;
if (task != null) {
diff --git a/services/core/java/com/android/server/wm/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java
index d89dc0b8e81c..91cd9498a356 100644
--- a/services/core/java/com/android/server/wm/TaskPersister.java
+++ b/services/core/java/com/android/server/wm/TaskPersister.java
@@ -245,18 +245,20 @@ public class TaskPersister implements PersisterQueue.Listener {
private static String fileToString(File file) {
final String newline = System.lineSeparator();
+ BufferedReader reader = null;
try {
- BufferedReader reader = new BufferedReader(new FileReader(file));
+ reader = new BufferedReader(new FileReader(file));
StringBuffer sb = new StringBuffer((int) file.length() * 2);
String line;
while ((line = reader.readLine()) != null) {
sb.append(line + newline);
}
- reader.close();
return sb.toString();
} catch (IOException ioe) {
Slog.e(TAG, "Couldn't read file " + file.getName());
return null;
+ } finally {
+ IoUtils.closeQuietly(reader);
}
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 7d300e98f44b..432ed1d0b61d 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -66,16 +66,19 @@ class TaskSnapshotController extends AbsAppSnapshotController<Task, TaskSnapshot
TaskSnapshotController(WindowManagerService service, SnapshotPersistQueue persistQueue) {
super(service);
- mPersistInfoProvider = createPersistInfoProvider(service,
- Environment::getDataSystemCeDirectory);
- mPersister = new TaskSnapshotPersister(persistQueue, mPersistInfoProvider);
-
- initialize(new TaskSnapshotCache(new AppSnapshotLoader(mPersistInfoProvider)));
final boolean snapshotEnabled =
!service.mContext
.getResources()
.getBoolean(com.android.internal.R.bool.config_disableTaskSnapshots);
setSnapshotEnabled(snapshotEnabled);
+ mPersistInfoProvider = createPersistInfoProvider(service,
+ Environment::getDataSystemCeDirectory);
+
+ mPersister = new TaskSnapshotPersister(
+ persistQueue,
+ mPersistInfoProvider,
+ shouldDisableSnapshots());
+ initialize(new TaskSnapshotCache(new AppSnapshotLoader(mPersistInfoProvider)));
}
static PersistInfoProvider createPersistInfoProvider(WindowManagerService service,
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 87be74ae1dd9..538fd8dc5406 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -26,6 +26,7 @@ import android.window.TaskSnapshot;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.UserManagerInternal;
+import com.android.window.flags.Flags;
import java.io.File;
import java.util.Arrays;
@@ -37,6 +38,8 @@ import java.util.Arrays;
*/
class TaskSnapshotPersister extends BaseAppSnapshotPersister {
+ private final boolean mDisableSnapshots;
+
/**
* The list of ids of the tasks that have been persisted since {@link #removeObsoleteFiles} was
* called.
@@ -45,8 +48,10 @@ class TaskSnapshotPersister extends BaseAppSnapshotPersister {
private final ArraySet<Integer> mPersistedTaskIdsSinceLastRemoveObsolete = new ArraySet<>();
TaskSnapshotPersister(SnapshotPersistQueue persistQueue,
- PersistInfoProvider persistInfoProvider) {
+ PersistInfoProvider persistInfoProvider,
+ boolean disableSnapshots) {
super(persistQueue, persistInfoProvider);
+ mDisableSnapshots = Flags.checkDisabledSnapshotsInTaskPersister() && disableSnapshots;
}
/**
@@ -57,6 +62,9 @@ class TaskSnapshotPersister extends BaseAppSnapshotPersister {
* @param snapshot The snapshot to persist.
*/
void persistSnapshot(int taskId, int userId, TaskSnapshot snapshot) {
+ if (mDisableSnapshots) {
+ return;
+ }
synchronized (mLock) {
mPersistedTaskIdsSinceLastRemoveObsolete.add(taskId);
super.persistSnapshot(taskId, userId, snapshot);
@@ -71,6 +79,9 @@ class TaskSnapshotPersister extends BaseAppSnapshotPersister {
*/
@Override
void removeSnapshot(int taskId, int userId) {
+ if (mDisableSnapshots) {
+ return;
+ }
synchronized (mLock) {
mPersistedTaskIdsSinceLastRemoveObsolete.remove(taskId);
super.removeSnapshot(taskId, userId);
@@ -86,7 +97,7 @@ class TaskSnapshotPersister extends BaseAppSnapshotPersister {
* model.
*/
void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, int[] runningUserIds) {
- if (runningUserIds.length == 0) {
+ if (runningUserIds.length == 0 || mDisableSnapshots) {
return;
}
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index f4a455a9c2dd..75cefdff2b0b 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -2890,6 +2890,13 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
leashReference = leashReference.getParent();
}
}
+ if (wc == leashReference
+ && sortedTargets.get(i).mWindowingMode == WINDOWING_MODE_PINNED) {
+ // If a PiP task is the only target, we wanna make sure the transition root leash
+ // is at the top in case PiP is sent to back. This is done because a pinned task is
+ // meant to be always-on-top throughout a transition.
+ leashReference = ancestor.getTopChild();
+ }
final SurfaceControl rootLeash = leashReference.makeAnimationLeash().setName(
"Transition Root: " + leashReference.getName())
.setCallsite("Transition.calculateTransitionRoots").build();
diff --git a/services/core/java/com/android/server/wm/TransparentPolicy.java b/services/core/java/com/android/server/wm/TransparentPolicy.java
index edd99243c3ef..88ea0730ab00 100644
--- a/services/core/java/com/android/server/wm/TransparentPolicy.java
+++ b/services/core/java/com/android/server/wm/TransparentPolicy.java
@@ -204,7 +204,7 @@ class TransparentPolicy {
return true;
}
final AppCompatSizeCompatModePolicy scmPolicy = mActivityRecord.mAppCompatController
- .getAppCompatSizeCompatModePolicy();
+ .getSizeCompatModePolicy();
if (mActivityRecord.getTask() == null || mActivityRecord.fillsParent()
|| scmPolicy.hasAppCompatDisplayInsetsWithoutInheritance()) {
return true;
diff --git a/services/core/java/com/android/server/wm/Watermark.java b/services/core/java/com/android/server/wm/Watermark.java
index 9780d3317e11..eb6eeb31e8fb 100644
--- a/services/core/java/com/android/server/wm/Watermark.java
+++ b/services/core/java/com/android/server/wm/Watermark.java
@@ -126,8 +126,9 @@ class Watermark {
} catch (OutOfResourcesException e) {
}
mSurfaceControl = ctrl;
- mBlastBufferQueue = new BLASTBufferQueue(TITLE, mSurfaceControl, 1 /* width */,
- 1 /* height */, PixelFormat.RGBA_8888);
+ mBlastBufferQueue = new BLASTBufferQueue(TITLE, /* updateDestinationFrame */ true);
+ mBlastBufferQueue.update(mSurfaceControl, 1 /* width */, 1 /* height */,
+ PixelFormat.RGBA_8888);
mSurface = mBlastBufferQueue.createSurface();
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerFlags.java b/services/core/java/com/android/server/wm/WindowManagerFlags.java
index 7ef8d8d0c16a..df70ed2e99a8 100644
--- a/services/core/java/com/android/server/wm/WindowManagerFlags.java
+++ b/services/core/java/com/android/server/wm/WindowManagerFlags.java
@@ -58,6 +58,8 @@ class WindowManagerFlags {
final boolean mEnsureWallpaperInTransitions;
+ final boolean mAodTransition = Flags.aodTransition();
+
/* End Available Flags */
WindowManagerFlags() {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e4ef3d186bdb..36d52ddb40e6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -331,6 +331,7 @@ import android.window.WindowContextInfo;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
import com.android.internal.os.IResultReceiver;
import com.android.internal.os.TransferPipe;
import com.android.internal.policy.IKeyguardDismissCallback;
@@ -512,7 +513,6 @@ public class WindowManagerService extends IWindowManager.Stub
public void onVrStateChanged(boolean enabled) {
synchronized (mGlobalLock) {
mVrModeEnabled = enabled;
- mRoot.forAllDisplayPolicies(p -> p.onVrStateChangedLw(enabled));
}
}
};
@@ -600,6 +600,7 @@ public class WindowManagerService extends IWindowManager.Stub
final boolean mLimitedAlphaCompositing;
final int mMaxUiWidth;
+ @NonNull
@VisibleForTesting
WindowManagerPolicy mPolicy;
@@ -879,11 +880,6 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
- if (mImmersiveModeConfirmationsUri.equals(uri) || mPolicyControlUri.equals(uri)) {
- updateSystemUiSettings(true /* handleChange */);
- return;
- }
-
if (mForceDesktopModeOnExternalDisplaysUri.equals(uri)) {
updateForceDesktopModeOnExternalDisplays();
return;
@@ -936,7 +932,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
void loadSettings() {
- updateSystemUiSettings(false /* handleChange */);
updateMaximumObscuringOpacityForTouch();
updateDisableSecureWindows();
}
@@ -953,21 +948,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- void updateSystemUiSettings(boolean handleChange) {
- synchronized (mGlobalLock) {
- boolean changed = false;
- if (handleChange) {
- changed = getDefaultDisplayContentLocked().getDisplayPolicy()
- .onSystemUiSettingsChanged();
- } else {
- ImmersiveModeConfirmation.loadSetting(mCurrentUserId, mContext);
- }
- if (changed) {
- mWindowPlacerLocked.requestTraversal();
- }
- }
- }
-
void updateForceDesktopModeOnExternalDisplays() {
ContentResolver resolver = mContext.getContentResolver();
final boolean enableForceDesktopMode = Settings.Global.getInt(resolver,
@@ -1054,13 +1034,16 @@ public class WindowManagerService extends IWindowManager.Stub
private boolean mAnimationsDisabled = false;
boolean mPointerLocationEnabled = false;
+ @NonNull
final AppCompatConfiguration mAppCompatConfiguration;
private boolean mIsIgnoreOrientationRequestDisabled;
+ @NonNull
final InputManagerService mInputManager;
final DisplayManagerInternal mDisplayManagerInternal;
final DisplayManager mDisplayManager;
+ @NonNull
final ActivityTaskManagerService mAtmService;
/** Indicates whether this device supports wide color gamut / HDR rendering */
@@ -1116,7 +1099,9 @@ public class WindowManagerService extends IWindowManager.Stub
static WindowManagerThreadPriorityBooster sThreadPriorityBooster =
new WindowManagerThreadPriorityBooster();
+ @NonNull
Supplier<SurfaceControl.Builder> mSurfaceControlFactory;
+ @NonNull
Supplier<SurfaceControl.Transaction> mTransactionFactory;
private final SurfaceControl.Transaction mTransaction;
@@ -1188,9 +1173,11 @@ public class WindowManagerService extends IWindowManager.Stub
private volatile boolean mDisableSecureWindows = false;
- public static WindowManagerService main(final Context context, final InputManagerService im,
- final boolean showBootMsgs, WindowManagerPolicy policy,
- ActivityTaskManagerService atm) {
+ /** Creates an instance of the WindowManagerService for the system server. */
+ public static WindowManagerService main(@NonNull final Context context,
+ @NonNull final InputManagerService im, final boolean showBootMsgs,
+ @NonNull final WindowManagerPolicy policy,
+ @NonNull final ActivityTaskManagerService atm) {
// Using SysUI context to have access to Material colors extracted from Wallpaper.
final AppCompatConfiguration appCompat = new AppCompatConfiguration(
ActivityThread.currentActivityThread().getSystemUiContext());
@@ -1204,15 +1191,19 @@ public class WindowManagerService extends IWindowManager.Stub
/**
* Creates and returns an instance of the WindowManagerService. This call allows the caller
- * to override factories that can be used to stub native calls during test.
+ * to override factories that can be used to stub native calls during test. Tests should use
+ * {@link WindowManagerServiceTestSupport} instead of calling this directly to ensure
+ * proper initialization and cleanup of dependencies.
*/
- @VisibleForTesting
- public static WindowManagerService main(final Context context, final InputManagerService im,
- final boolean showBootMsgs, WindowManagerPolicy policy, ActivityTaskManagerService atm,
- DisplayWindowSettingsProvider displayWindowSettingsProvider,
- Supplier<SurfaceControl.Transaction> transactionFactory,
- Supplier<SurfaceControl.Builder> surfaceControlFactory,
- AppCompatConfiguration appCompat) {
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static WindowManagerService main(@NonNull final Context context,
+ @NonNull final InputManagerService im, boolean showBootMsgs,
+ @NonNull final WindowManagerPolicy policy,
+ @NonNull final ActivityTaskManagerService atm,
+ @NonNull final DisplayWindowSettingsProvider displayWindowSettingsProvider,
+ @NonNull final Supplier<SurfaceControl.Transaction> transactionFactory,
+ @NonNull final Supplier<SurfaceControl.Builder> surfaceControlFactory,
+ @NonNull final AppCompatConfiguration appCompat) {
final WindowManagerService[] wms = new WindowManagerService[1];
DisplayThread.getHandler().runWithScissors(() ->
@@ -1238,12 +1229,13 @@ public class WindowManagerService extends IWindowManager.Stub
new WindowManagerShellCommand(this).exec(this, in, out, err, args, callback, result);
}
- private WindowManagerService(Context context, InputManagerService inputManager,
- boolean showBootMsgs, WindowManagerPolicy policy, ActivityTaskManagerService atm,
- DisplayWindowSettingsProvider displayWindowSettingsProvider,
- Supplier<SurfaceControl.Transaction> transactionFactory,
- Supplier<SurfaceControl.Builder> surfaceControlFactory,
- AppCompatConfiguration appCompat) {
+ private WindowManagerService(@NonNull Context context,
+ @NonNull InputManagerService inputManager, boolean showBootMsgs,
+ @NonNull WindowManagerPolicy policy, @NonNull ActivityTaskManagerService atm,
+ @NonNull DisplayWindowSettingsProvider displayWindowSettingsProvider,
+ @NonNull Supplier<SurfaceControl.Transaction> transactionFactory,
+ @NonNull Supplier<SurfaceControl.Builder> surfaceControlFactory,
+ @NonNull AppCompatConfiguration appCompat) {
installLock(this, INDEX_WINDOW);
mGlobalLock = atm.getGlobalLock();
mAtmService = atm;
@@ -3301,7 +3293,6 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void onUserSwitched() {
- mSettingsObserver.updateSystemUiSettings(true /* handleChange */);
synchronized (mGlobalLock) {
// force a re-application of focused window sysui visibility on each display.
mRoot.forAllDisplayPolicies(DisplayPolicy::resetSystemBarAttributes);
@@ -6393,11 +6384,6 @@ public class WindowManagerService extends IWindowManager.Stub
if (mFrozenDisplayId != INVALID_DISPLAY && mFrozenDisplayId == w.getDisplayId()
&& mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
ProtoLog.v(WM_DEBUG_ORIENTATION, "Changing surface while display frozen: %s", w);
- // WindowsState#reportResized won't tell invisible requested window to redraw,
- // so do not set it as changing orientation to avoid affecting draw state.
- if (w.isVisibleRequested()) {
- w.setOrientationChanging(true);
- }
if (mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_NONE) {
mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
// XXX should probably keep timeout from
@@ -9062,22 +9048,6 @@ public class WindowManagerService extends IWindowManager.Stub
return mSurfaceControlFactory.get();
}
- /**
- * Called when the state of lock task mode changes. This should be used to disable immersive
- * mode confirmation.
- *
- * @param lockTaskState the new lock task mode state. One of
- * {@link ActivityManager#LOCK_TASK_MODE_NONE},
- * {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
- * {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
- */
- void onLockTaskStateChanged(int lockTaskState) {
- // TODO: pass in displayId to determine which display the lock task state changed
- synchronized (mGlobalLock) {
- mRoot.forAllDisplayPolicies(p -> p.onLockTaskStateChangedLw(lockTaskState));
- }
- }
-
@Override
public void syncInputTransactions(boolean waitForAnimations) {
final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index f0f1b2e47cc8..3c3a180f4da1 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -38,6 +38,7 @@ import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_
import static android.window.TaskFragmentOperation.OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ANIMATION_PARAMS;
+import static android.window.TaskFragmentOperation.OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_COMPANION_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_DECOR_SURFACE_BOOSTED;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_DIM_ON_TASK;
@@ -1862,6 +1863,13 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
taskFragment.setPinned(pinned);
break;
}
+ case OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS: {
+ taskFragment.setCanAffectSystemUiFlags(operation.getBooleanValue());
+
+ // Request to apply the flags.
+ mService.mWindowManager.mWindowPlacerLocked.requestTraversal();
+ break;
+ }
}
return effects;
}
@@ -1937,6 +1945,16 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
return false;
}
+ if ((opType == OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS)
+ && !mTaskFragmentOrganizerController.isSystemOrganizer(organizer.asBinder())) {
+ final Throwable exception = new SecurityException(
+ "Only a system organizer can perform OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS."
+ );
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
+ opType, exception);
+ return false;
+ }
+
final IBinder secondaryFragmentToken = operation.getSecondaryFragmentToken();
return secondaryFragmentToken == null
|| validateTaskFragment(mLaunchTaskFragments.get(secondaryFragmentToken), opType,
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 85e3d89730a3..da58470edc1e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -148,7 +148,6 @@ import static com.android.server.wm.WindowManagerService.MY_PID;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
-import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
import static com.android.server.wm.WindowStateAnimator.COMMIT_DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
@@ -592,27 +591,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
/** Completely remove from window manager after exit animation? */
boolean mRemoveOnExit;
- /**
- * Set when the orientation is changing and this window has not yet
- * been updated for the new orientation.
- */
- private boolean mOrientationChanging;
-
/** The time when the window was last requested to redraw for orientation change. */
private long mOrientationChangeRedrawRequestTime;
/**
- * Sometimes in addition to the mOrientationChanging
- * flag we report that the orientation is changing
- * due to a mismatch in current and reported configuration.
- *
- * In the case of timeout we still need to make sure we
- * leave the orientation changing state though, so we
- * use this as a special time out escape hatch.
- */
- private boolean mOrientationChangeTimedOut;
-
- /**
* The orientation during the last visible call to relayout. If our
* current orientation is different, the window can't be ready
* to be shown.
@@ -1497,8 +1479,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// Reset the drawn state if the window need to redraw for the change, so the transition
// can wait until it has finished drawing to start.
- if ((configChanged || getOrientationChanging() || dragResizingChanged)
- && isVisibleRequested()) {
+ if ((configChanged || dragResizingChanged) && isVisibleRequested()) {
winAnimator.mDrawState = DRAW_PENDING;
if (mActivityRecord != null) {
mActivityRecord.clearAllDrawn();
@@ -1512,15 +1493,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
ProtoLog.v(WM_DEBUG_RESIZE, "Resizing window %s", this);
mWmService.mResizingWindows.add(this);
}
- } else if (getOrientationChanging()) {
- if (isDrawn()) {
- ProtoLog.v(WM_DEBUG_ORIENTATION,
- "Orientation not waiting for draw in %s, surfaceController %s", this,
- winAnimator.mSurfaceControl);
- setOrientationChanging(false);
- mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
- - mWmService.mDisplayFreezeTime);
- }
}
}
@@ -1528,46 +1500,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return !mWindowFrames.mFrame.equals(mWindowFrames.mLastFrame);
}
- boolean getOrientationChanging() {
- if (mTransitionController.isShellTransitionsEnabled()) {
- // Shell transition doesn't use the methods for display frozen state.
- return false;
- }
- // In addition to the local state flag, we must also consider the difference in the last
- // reported configuration vs. the current state. If the client code has not been informed of
- // the change, logic dependent on having finished processing the orientation, such as
- // unfreezing, could be improperly triggered.
- // TODO(b/62846907): Checking against {@link mLastReportedConfiguration} could be flaky as
- // this is not necessarily what the client has processed yet. Find a
- // better indicator consistent with the client.
- return (mOrientationChanging || (isVisible()
- && getConfiguration().orientation != getLastReportedConfiguration().orientation))
- && !mSeamlesslyRotated
- && !mOrientationChangeTimedOut;
- }
-
- void setOrientationChanging(boolean changing) {
- mOrientationChangeTimedOut = false;
- if (mOrientationChanging == changing) {
- return;
- }
- mOrientationChanging = changing;
- if (changing) {
- mLastFreezeDuration = 0;
- if (mWmService.mRoot.mOrientationChangeComplete
- && mDisplayContent.shouldSyncRotationChange(this)) {
- mWmService.mRoot.mOrientationChangeComplete = false;
- }
- } else {
- // The orientation change is completed. If it was hidden by the animation, reshow it.
- mDisplayContent.finishAsyncRotation(mToken);
- }
- }
-
- void orientationChangeTimedOut() {
- mOrientationChangeTimedOut = true;
- }
-
@Override
void onDisplayChanged(DisplayContent dc) {
if (dc != null && mDisplayContent != null && dc != mDisplayContent
@@ -3355,12 +3287,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mAppFreezing = false;
- if (mHasSurface && !getOrientationChanging()
- && mWmService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
- ProtoLog.v(WM_DEBUG_ORIENTATION,
- "set mOrientationChanging of %s", this);
- setOrientationChanging(true);
- }
mLastFreezeDuration = 0;
setDisplayLayoutNeeded();
return true;
@@ -4266,9 +4192,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
+ " mDestroying=" + mDestroying
+ " mRemoved=" + mRemoved);
}
- if (getOrientationChanging() || mAppFreezing) {
- pw.println(prefix + "mOrientationChanging=" + mOrientationChanging
- + " configOrientationChanging="
+ if (mAppFreezing) {
+ pw.println(prefix + " configOrientationChanging="
+ (getLastReportedConfiguration().orientation != getConfiguration().orientation)
+ " mAppFreezing=" + mAppFreezing);
}
@@ -5356,7 +5281,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// Send information to SurfaceFlinger about the priority of the current window.
updateFrameRateSelectionPriorityIfNeeded();
updateScaleIfNeeded();
- mWinAnimator.prepareSurfaceLocked(getSyncTransaction());
+ mWinAnimator.prepareSurfaceLocked(getPendingTransaction());
applyDims();
}
super.prepareSurfaces();
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 0154d95d888d..298580e4bb81 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -29,7 +29,6 @@ import static android.view.WindowManager.TRANSIT_OLD_NONE;
import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ANIM;
import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_DRAW;
-import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_STARTING_WINDOW;
import static com.android.internal.protolog.WmProtoLogGroups.WM_SHOW_SURFACE_ALLOC;
import static com.android.internal.protolog.WmProtoLogGroups.WM_SHOW_TRANSACTIONS;
@@ -417,56 +416,19 @@ class WindowStateAnimator {
}
}
- void computeShownFrameLocked() {
- if (mWin.mIsWallpaper && mService.mRoot.mWallpaperActionPending) {
- return;
- } else if (mWin.isDragResizeChanged()) {
- // This window is awaiting a relayout because user just started (or ended)
- // drag-resizing. The shown frame (which affects surface size and pos)
- // should not be updated until we get next finished draw with the new surface.
- // Otherwise one or two frames rendered with old settings would be displayed
- // with new geometry.
- return;
- }
-
- if (DEBUG) {
- Slog.v(TAG, "computeShownFrameLocked: " + this
- + " not attached, mAlpha=" + mAlpha);
- }
-
- mShownAlpha = mAlpha;
- }
-
void prepareSurfaceLocked(SurfaceControl.Transaction t) {
final WindowState w = mWin;
if (!hasSurface()) {
-
- // There is no need to wait for an animation change if our window is gone for layout
- // already as we'll never be visible.
- if (w.getOrientationChanging() && w.isGoneForLayout()) {
- ProtoLog.v(WM_DEBUG_ORIENTATION, "Orientation change skips hidden %s", w);
- w.setOrientationChanging(false);
- }
return;
}
- computeShownFrameLocked();
+ mShownAlpha = mAlpha;
if (!w.isOnScreen()) {
hide(t, "prepareSurfaceLocked");
if (!w.mIsWallpaper || !mService.mFlags.mEnsureWallpaperInTransitions) {
mWallpaperControllerLocked.hideWallpapers(w);
}
-
- // If we are waiting for this window to handle an orientation change. If this window is
- // really hidden (gone for layout), there is no point in still waiting for it.
- // Note that this does introduce a potential glitch if the window becomes unhidden
- // before it has drawn for the new orientation.
- if (w.getOrientationChanging() && w.isGoneForLayout()) {
- w.setOrientationChanging(false);
- ProtoLog.v(WM_DEBUG_ORIENTATION,
- "Orientation change skips hidden %s", w);
- }
} else if (mLastAlpha != mShownAlpha
|| mLastHidden) {
mLastAlpha = mShownAlpha;
@@ -480,35 +442,9 @@ class WindowStateAnimator {
if (mLastHidden) {
showRobustly(t);
mLastHidden = false;
- final DisplayContent displayContent = w.getDisplayContent();
- if (!displayContent.getLastHasContent()) {
- // This draw means the difference between unique content and mirroring.
- // Run another pass through performLayout to set mHasContent in the
- // LogicalDisplay.
- displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM;
- if (DEBUG_LAYOUT_REPEATS) {
- mService.mWindowPlacerLocked.debugLayoutRepeats(
- "showSurfaceRobustlyLocked " + w,
- displayContent.pendingLayoutChanges);
- }
- }
}
}
}
-
- if (w.getOrientationChanging()) {
- if (!w.isDrawn()) {
- if (w.mDisplayContent.shouldSyncRotationChange(w)) {
- w.mWmService.mRoot.mOrientationChangeComplete = false;
- mAnimator.mLastWindowFreezeSource = w;
- }
- ProtoLog.v(WM_DEBUG_ORIENTATION,
- "Orientation continue waiting for draw in %s", w);
- } else {
- w.setOrientationChanging(false);
- ProtoLog.v(WM_DEBUG_ORIENTATION, "Orientation change complete in %s", w);
- }
- }
}
private void showRobustly(SurfaceControl.Transaction t) {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index dff718a4b7d5..a34b5115faf9 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -127,7 +127,6 @@ class WindowSurfacePlacer {
mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
loopCount--;
} while (mTraversalScheduled && loopCount > 0);
- mService.mRoot.mWallpaperActionPending = false;
}
private void performSurfacePlacementLoop() {
diff --git a/services/core/xsd/device-state-config/device-state-config.xsd b/services/core/xsd/device-state-config/device-state-config.xsd
index 4a947327070a..324c9b422ecb 100644
--- a/services/core/xsd/device-state-config/device-state-config.xsd
+++ b/services/core/xsd/device-state-config/device-state-config.xsd
@@ -41,6 +41,7 @@
<xs:annotation name="nullable" />
</xs:element>
<xs:element name="properties" type="properties" />
+ <xs:element name="flags" type="flags" />
<xs:element name="conditions" type="conditions" />
</xs:sequence>
</xs:complexType>
@@ -53,6 +54,14 @@
</xs:sequence>
</xs:complexType>
+ <xs:complexType name="flags">
+ <xs:sequence>
+ <xs:element name="flag" type="xs:string" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation name="nullable" />
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
<xs:complexType name="conditions">
<xs:sequence>
<xs:element name="lid-switch" type="lidSwitchCondition" minOccurs="0">
diff --git a/services/core/xsd/device-state-config/schema/current.txt b/services/core/xsd/device-state-config/schema/current.txt
index 5bb216e69e4d..c94f3a80b898 100644
--- a/services/core/xsd/device-state-config/schema/current.txt
+++ b/services/core/xsd/device-state-config/schema/current.txt
@@ -11,10 +11,12 @@ package com.android.server.policy.devicestate.config {
public class DeviceState {
ctor public DeviceState();
method public com.android.server.policy.devicestate.config.Conditions getConditions();
+ method public com.android.server.policy.devicestate.config.Flags getFlags();
method public java.math.BigInteger getIdentifier();
method @Nullable public String getName();
method public com.android.server.policy.devicestate.config.Properties getProperties();
method public void setConditions(com.android.server.policy.devicestate.config.Conditions);
+ method public void setFlags(com.android.server.policy.devicestate.config.Flags);
method public void setIdentifier(java.math.BigInteger);
method public void setName(@Nullable String);
method public void setProperties(com.android.server.policy.devicestate.config.Properties);
@@ -25,6 +27,11 @@ package com.android.server.policy.devicestate.config {
method public java.util.List<com.android.server.policy.devicestate.config.DeviceState> getDeviceState();
}
+ public class Flags {
+ ctor public Flags();
+ method @Nullable public java.util.List<java.lang.String> getFlag();
+ }
+
public class LidSwitchCondition {
ctor public LidSwitchCondition();
method public boolean getOpen();
diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java
index c0bc8e094a39..2aa0c6b6dd0b 100644
--- a/services/credentials/java/com/android/server/credentials/RequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/RequestSession.java
@@ -258,12 +258,33 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
if (propagateCancellation) {
mProviders.values().forEach(ProviderSession::cancelProviderRemoteSession);
}
- mRequestSessionMetric.logApiCalledAtFinish(apiStatus);
mRequestSessionStatus = RequestSessionStatus.COMPLETE;
+ if (Flags.fixMetricDuplicationEmits()) {
+ logTrackOneCandidatesAndPrepareFinalPhaseLogs(apiStatus);
+ }
+ mRequestSessionMetric.logApiCalledAtFinish(apiStatus);
mProviders.clear();
clearRequestSessionLocked();
}
+ /**
+ * Ensures all logging done in final phase methods only occur within the 'finishSession'.
+ */
+ private void logTrackOneCandidatesAndPrepareFinalPhaseLogs(int apiStatus) {
+ mRequestSessionMetric.logCandidateAggregateMetrics(mProviders);
+ if (isRespondingWithError(apiStatus)) {
+ mRequestSessionMetric.collectFinalPhaseProviderMetricStatus(
+ /*hasException=*/ true, ProviderStatusForMetrics.FINAL_FAILURE);
+ } else if (isRespondingWithUserCanceledError(apiStatus)) {
+ mRequestSessionMetric.collectFinalPhaseProviderMetricStatus(
+ /*hasException=*/false, ProviderStatusForMetrics.FINAL_FAILURE
+ );
+ } else if (isRespondingWithSuccess(apiStatus)) {
+ mRequestSessionMetric.collectFinalPhaseProviderMetricStatus(/*hasException=*/ false,
+ ProviderStatusForMetrics.FINAL_SUCCESS);
+ }
+ }
+
void cancelExistingPendingIntent() {
if (mPendingIntent != null) {
try {
@@ -343,9 +364,11 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
* @param response the response associated with the API call that just completed
*/
protected void respondToClientWithResponseAndFinish(V response) {
- mRequestSessionMetric.logCandidateAggregateMetrics(mProviders);
- mRequestSessionMetric.collectFinalPhaseProviderMetricStatus(/*has_exception=*/ false,
- ProviderStatusForMetrics.FINAL_SUCCESS);
+ if (!Flags.fixMetricDuplicationEmits()) {
+ mRequestSessionMetric.logCandidateAggregateMetrics(mProviders);
+ mRequestSessionMetric.collectFinalPhaseProviderMetricStatus(/*hasException=*/ false,
+ ProviderStatusForMetrics.FINAL_SUCCESS);
+ }
if (mRequestSessionStatus == RequestSessionStatus.COMPLETE) {
Slog.w(TAG, "Request has already been completed. This is strange.");
return;
@@ -360,8 +383,10 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
finishSession(/*propagateCancellation=*/false,
ApiStatus.SUCCESS.getMetricCode());
} catch (RemoteException e) {
- mRequestSessionMetric.collectFinalPhaseProviderMetricStatus(
- /*has_exception=*/ true, ProviderStatusForMetrics.FINAL_FAILURE);
+ if (!Flags.fixMetricDuplicationEmits()) {
+ mRequestSessionMetric.collectFinalPhaseProviderMetricStatus(
+ /*hasException=*/ true, ProviderStatusForMetrics.FINAL_FAILURE);
+ }
Slog.e(TAG, "Issue while responding to client with a response : " + e);
finishSession(/*propagateCancellation=*/false, ApiStatus.FAILURE.getMetricCode());
}
@@ -374,9 +399,11 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
* @param errorMsg the error message given back in the flow
*/
protected void respondToClientWithErrorAndFinish(String errorType, String errorMsg) {
- mRequestSessionMetric.logCandidateAggregateMetrics(mProviders);
- mRequestSessionMetric.collectFinalPhaseProviderMetricStatus(
- /*has_exception=*/ true, ProviderStatusForMetrics.FINAL_FAILURE);
+ if (!Flags.fixMetricDuplicationEmits()) {
+ mRequestSessionMetric.logCandidateAggregateMetrics(mProviders);
+ mRequestSessionMetric.collectFinalPhaseProviderMetricStatus(
+ /*hasException=*/ true, ProviderStatusForMetrics.FINAL_FAILURE);
+ }
if (mRequestSessionStatus == RequestSessionStatus.COMPLETE) {
Slog.w(TAG, "Request has already been completed. This is strange.");
return;
@@ -385,7 +412,6 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
finishSession(/*propagateCancellation=*/true, ApiStatus.CLIENT_CANCELED.getMetricCode());
return;
}
-
try {
invokeClientCallbackError(errorType, errorMsg);
} catch (RemoteException e) {
@@ -393,7 +419,9 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
}
boolean isUserCanceled = errorType.contains(MetricUtilities.USER_CANCELED_SUBSTRING);
if (isUserCanceled) {
- mRequestSessionMetric.setHasExceptionFinalPhase(/* has_exception */ false);
+ if (!Flags.fixMetricDuplicationEmits()) {
+ mRequestSessionMetric.setHasExceptionFinalPhase(/* hasException */ false);
+ }
finishSession(/*propagateCancellation=*/false,
ApiStatus.USER_CANCELED.getMetricCode());
} else {
@@ -421,4 +449,26 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
finishSession(isUiWaitingForData(), ApiStatus.CLIENT_CANCELED.getMetricCode());
}
}
+
+ /**
+ * This captures the final state of the apiStatus as presented in 'finishSession'.
+ */
+ private boolean isRespondingWithError(int apiStatus) {
+ return apiStatus == ApiStatus.FAILURE.getMetricCode()
+ || apiStatus == ApiStatus.CLIENT_CANCELED.getMetricCode();
+ }
+
+ /**
+ * A unique failure case, where we do not set the exception bit to be true.
+ */
+ private boolean isRespondingWithUserCanceledError(int apiStatus) {
+ return apiStatus == ApiStatus.USER_CANCELED.getMetricCode();
+ }
+
+ /**
+ * This captures the final state of the apiStatus as presented in 'finishSession'.
+ */
+ private boolean isRespondingWithSuccess(int apiStatus) {
+ return apiStatus == ApiStatus.SUCCESS.getMetricCode();
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 0ce25db6ea55..e960abd3b313 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -16412,7 +16412,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public android.app.admin.EnforcingAdmin getEnforcingAdmin(int userId, String identifier) {
- Preconditions.checkCallAuthorization(isSystemUid(getCallerIdentity()));
+ Preconditions.checkCallAuthorization(canQueryAdminPolicy(getCallerIdentity()));
return getEnforcingAdminInternal(userId, identifier);
}
diff --git a/services/foldables/devicestateprovider/src/com/android/server/policy/BookStyleClosedStatePredicate.java b/services/foldables/devicestateprovider/src/com/android/server/policy/BookStyleClosedStatePredicate.java
index ce4126a425c6..55d23585fb70 100644
--- a/services/foldables/devicestateprovider/src/com/android/server/policy/BookStyleClosedStatePredicate.java
+++ b/services/foldables/devicestateprovider/src/com/android/server/policy/BookStyleClosedStatePredicate.java
@@ -34,8 +34,10 @@ import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.display.DisplayManager;
import android.os.Handler;
+import android.os.PowerManager;
import android.util.ArraySet;
import android.util.Dumpable;
+import android.util.Slog;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.Surface;
@@ -44,6 +46,7 @@ import com.android.server.policy.BookStylePreferredScreenCalculator.PreferredScr
import com.android.server.policy.BookStylePreferredScreenCalculator.HingeAngle;
import com.android.server.policy.BookStylePreferredScreenCalculator.StateTransition;
import com.android.server.policy.BookStyleClosedStatePredicate.ConditionSensorListener.SensorSubscription;
+import com.android.server.policy.feature.flags.FeatureFlags;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -62,12 +65,19 @@ import java.util.function.Supplier;
public class BookStyleClosedStatePredicate implements Predicate<FoldableDeviceStateProvider>,
DisplayManager.DisplayListener, Dumpable {
+ private static final String TAG = "BookStyleClosedStatePredicate";
+
private final BookStylePreferredScreenCalculator mClosedStateCalculator;
private final Handler mHandler = new Handler();
private final PostureEstimator mPostureEstimator;
private final DisplayManager mDisplayManager;
+ private final PowerManager mPowerManager;
+ private final FeatureFlags mFeatureFlags;
private final DisplayInfo mDefaultDisplayInfo = new DisplayInfo();
+ @PowerManager.ScreenTimeoutPolicy
+ private volatile int mScreenTimeoutPolicy;
+
/**
* Creates {@link BookStyleClosedStatePredicate}. It is expected that the device has a pair
* of accelerometer sensors (one for each movable part of the device), see parameter
@@ -92,8 +102,11 @@ public class BookStyleClosedStatePredicate implements Predicate<FoldableDeviceSt
public BookStyleClosedStatePredicate(@NonNull Context context,
@NonNull ClosedStateUpdatesListener updatesListener,
@Nullable Sensor leftAccelerometerSensor, @Nullable Sensor rightAccelerometerSensor,
- @NonNull List<StateTransition> stateTransitions) {
+ @NonNull List<StateTransition> stateTransitions,
+ @NonNull FeatureFlags featureFlags) {
+ mFeatureFlags = featureFlags;
mDisplayManager = context.getSystemService(DisplayManager.class);
+ mPowerManager = context.getSystemService(PowerManager.class);
mDisplayManager.registerDisplayListener(this, mHandler);
mClosedStateCalculator = new BookStylePreferredScreenCalculator(stateTransitions);
@@ -108,6 +121,23 @@ public class BookStyleClosedStatePredicate implements Predicate<FoldableDeviceSt
}
/**
+ * Initialize the predicate, the predicate could subscribe to various data sources the data
+ * from which could be used later when calling {@link BookStyleClosedStatePredicate#test}.
+ */
+ public void init() {
+ if (mFeatureFlags.forceFoldablesTentModeWithScreenWakelock()) {
+ try {
+ mPowerManager.addScreenTimeoutPolicyListener(DEFAULT_DISPLAY, Runnable::run,
+ new ScreenTimeoutPolicyListener());
+ } catch (IllegalStateException exception) {
+ // TODO: b/389613319 - remove after removing the screen timeout policy API flagging
+ Slog.e(TAG, "Error subscribing to the screen timeout policy changes");
+ exception.printStackTrace();
+ }
+ }
+ }
+
+ /**
* Based on the current sensor readings and current state, returns true if the device should use
* 'CLOSED' device state and false if it should not use 'CLOSED' state (e.g. could use half-open
* or open states).
@@ -119,13 +149,24 @@ public class BookStyleClosedStatePredicate implements Predicate<FoldableDeviceSt
mPostureEstimator.onDeviceClosedStatusChanged(hingeAngle == ANGLE_0);
+ final boolean isLikelyTentOrWedgeMode = mPostureEstimator.isLikelyTentOrWedgeMode()
+ || shouldForceTentOrWedgeMode();
+
final PreferredScreen preferredScreen = mClosedStateCalculator.
- calculatePreferredScreen(hingeAngle, mPostureEstimator.isLikelyTentOrWedgeMode(),
+ calculatePreferredScreen(hingeAngle, isLikelyTentOrWedgeMode,
mPostureEstimator.isLikelyReverseWedgeMode(hingeAngle));
return preferredScreen == OUTER;
}
+ private boolean shouldForceTentOrWedgeMode() {
+ if (!mFeatureFlags.forceFoldablesTentModeWithScreenWakelock()) {
+ return false;
+ }
+
+ return mScreenTimeoutPolicy == PowerManager.SCREEN_TIMEOUT_KEEP_DISPLAY_ON;
+ }
+
private HingeAngle hingeAngleFromFloat(float hingeAngle) {
if (hingeAngle == 0f) {
return ANGLE_0;
@@ -163,7 +204,7 @@ public class BookStyleClosedStatePredicate implements Predicate<FoldableDeviceSt
@Override
public void dump(@NonNull PrintWriter writer, @Nullable String[] args) {
writer.println(" " + getDumpableName());
-
+ writer.println(" mScreenTimeoutPolicy=" + mScreenTimeoutPolicy);
mPostureEstimator.dump(writer, args);
mClosedStateCalculator.dump(writer, args);
}
@@ -172,6 +213,15 @@ public class BookStyleClosedStatePredicate implements Predicate<FoldableDeviceSt
void onClosedStateUpdated();
}
+ private class ScreenTimeoutPolicyListener implements
+ PowerManager.ScreenTimeoutPolicyListener {
+ @Override
+ public void onScreenTimeoutPolicyChanged(int screenTimeoutPolicy) {
+ // called from the binder thread
+ mScreenTimeoutPolicy = screenTimeoutPolicy;
+ }
+ }
+
/**
* Estimates if the device is going to enter wedge/tent mode based on the sensor data
*/
diff --git a/services/foldables/devicestateprovider/src/com/android/server/policy/BookStyleDeviceStatePolicy.java b/services/foldables/devicestateprovider/src/com/android/server/policy/BookStyleDeviceStatePolicy.java
index f34ec72d7e27..dfc4ba2cfa71 100644
--- a/services/foldables/devicestateprovider/src/com/android/server/policy/BookStyleDeviceStatePolicy.java
+++ b/services/foldables/devicestateprovider/src/com/android/server/policy/BookStyleDeviceStatePolicy.java
@@ -114,7 +114,7 @@ public class BookStyleDeviceStatePolicy extends DeviceStatePolicy implements
mIsDualDisplayBlockingEnabled = featureFlags.enableDualDisplayBlocking();
final DeviceStatePredicateWrapper[] configuration = createConfiguration(
- leftAccelerometerSensor, rightAccelerometerSensor, closeAngleDegrees);
+ leftAccelerometerSensor, rightAccelerometerSensor, closeAngleDegrees, featureFlags);
mProvider = new FoldableDeviceStateProvider(mContext, sensorManager, hingeAngleSensor,
hallSensor, displayManager, configuration);
@@ -122,10 +122,10 @@ public class BookStyleDeviceStatePolicy extends DeviceStatePolicy implements
private DeviceStatePredicateWrapper[] createConfiguration(
@Nullable Sensor leftAccelerometerSensor, @Nullable Sensor rightAccelerometerSensor,
- Integer closeAngleDegrees) {
+ Integer closeAngleDegrees, @NonNull FeatureFlags featureFlags) {
return new DeviceStatePredicateWrapper[]{
createClosedConfiguration(leftAccelerometerSensor, rightAccelerometerSensor,
- closeAngleDegrees),
+ closeAngleDegrees, featureFlags),
createConfig(getHalfOpenedDeviceState(), /* activeStatePredicate= */
(provider) -> {
final float hingeAngle = provider.getHingeAngle();
@@ -147,7 +147,7 @@ public class BookStyleDeviceStatePolicy extends DeviceStatePolicy implements
private DeviceStatePredicateWrapper createClosedConfiguration(
@Nullable Sensor leftAccelerometerSensor, @Nullable Sensor rightAccelerometerSensor,
- @Nullable Integer closeAngleDegrees) {
+ @Nullable Integer closeAngleDegrees, @NonNull FeatureFlags featureFlags) {
if (closeAngleDegrees != null) {
// Switch displays at closeAngleDegrees in both ways (folding and unfolding)
@@ -161,9 +161,12 @@ public class BookStyleDeviceStatePolicy extends DeviceStatePolicy implements
if (mEnablePostureBasedClosedState) {
// Use smart closed state predicate that will use different switch angles
// based on the device posture (e.g. wedge mode, tent mode, reverse wedge mode)
- return createConfig(getClosedDeviceState(), /* activeStatePredicate= */
- new BookStyleClosedStatePredicate(mContext, this, leftAccelerometerSensor,
- rightAccelerometerSensor, DEFAULT_STATE_TRANSITIONS));
+ final BookStyleClosedStatePredicate predicate = new BookStyleClosedStatePredicate(
+ mContext, this, leftAccelerometerSensor, rightAccelerometerSensor,
+ DEFAULT_STATE_TRANSITIONS, featureFlags);
+ return createConfig(getClosedDeviceState(),
+ /* activeStatePredicate= */ predicate,
+ /* initializer= */ predicate::init);
}
// Switch to the outer display only at 0 degrees but use TENT_MODE_SWITCH_ANGLE_DEGREES
diff --git a/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java b/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java
index daeaa9833d78..8e749529978e 100644
--- a/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java
+++ b/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java
@@ -200,6 +200,16 @@ public final class FoldableDeviceStateProvider implements DeviceStateProvider,
}
}
+ @Override
+ public void onSystemReady() {
+ for (int i = 0; i < mConfigurations.length; i++) {
+ final DeviceStatePredicateWrapper configuration = mConfigurations[i];
+ if (configuration.mInitializer != null) {
+ configuration.mInitializer.run();
+ }
+ }
+ }
+
private void assertUniqueDeviceStateIdentifier(DeviceStatePredicateWrapper configuration) {
if (mStateConditions.get(configuration.mDeviceState.getIdentifier()) != null) {
throw new IllegalArgumentException("Device state configurations must have unique"
@@ -461,11 +471,12 @@ public final class FoldableDeviceStateProvider implements DeviceStateProvider,
private final DeviceState mDeviceState;
private final Predicate<FoldableDeviceStateProvider> mActiveStatePredicate;
private final Predicate<FoldableDeviceStateProvider> mAvailabilityPredicate;
+ private final Runnable mInitializer;
private DeviceStatePredicateWrapper(
@NonNull DeviceState deviceState,
@NonNull Predicate<FoldableDeviceStateProvider> predicate) {
- this(deviceState, predicate, ALLOWED);
+ this(deviceState, predicate, ALLOWED, /* initializer= */ null);
}
/** Create a configuration with availability and availability predicate **/
@@ -473,10 +484,28 @@ public final class FoldableDeviceStateProvider implements DeviceStateProvider,
@NonNull DeviceState deviceState,
@NonNull Predicate<FoldableDeviceStateProvider> activeStatePredicate,
@NonNull Predicate<FoldableDeviceStateProvider> availabilityPredicate) {
+ this(deviceState, activeStatePredicate, availabilityPredicate, /* initializer= */ null);
+ }
+
+ /**
+ * Create a configuration with availability and availability predicate.
+ * @param deviceState specifies device state for this configuration
+ * @param activeStatePredicate predicate that should return 'true' when this device state
+ * wants to be and can be active
+ * @param availabilityPredicate predicate that should return 'true' only when this device
+ * state is allowed
+ * @param initializer callback that will be called when the system is booted and ready
+ */
+ private DeviceStatePredicateWrapper(
+ @NonNull DeviceState deviceState,
+ @NonNull Predicate<FoldableDeviceStateProvider> activeStatePredicate,
+ @NonNull Predicate<FoldableDeviceStateProvider> availabilityPredicate,
+ @Nullable Runnable initializer) {
mDeviceState = deviceState;
mActiveStatePredicate = activeStatePredicate;
mAvailabilityPredicate = availabilityPredicate;
+ mInitializer = initializer;
}
/** Create a configuration with an active state predicate **/
@@ -487,6 +516,16 @@ public final class FoldableDeviceStateProvider implements DeviceStateProvider,
return new DeviceStatePredicateWrapper(deviceState, activeStatePredicate);
}
+ /** Create a configuration with an active state predicate and an initializer **/
+ public static DeviceStatePredicateWrapper createConfig(
+ @NonNull DeviceState deviceState,
+ @NonNull Predicate<FoldableDeviceStateProvider> activeStatePredicate,
+ @Nullable Runnable initializer
+ ) {
+ return new DeviceStatePredicateWrapper(deviceState, activeStatePredicate, ALLOWED,
+ initializer);
+ }
+
/** Create a configuration with availability and active state predicate **/
public static DeviceStatePredicateWrapper createConfig(
@NonNull DeviceState deviceState,
diff --git a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig
index 21e33dd1b99a..da2e5ee37c1a 100644
--- a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig
+++ b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig
@@ -9,6 +9,16 @@ flag {
}
flag {
+ name: "force_foldables_tent_mode_with_screen_wakelock"
+ namespace: "windowing_frontend"
+ description: "Switching displays on a foldable device later if screen wakelock is present"
+ bug: "363174979"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "enable_foldables_posture_based_closed_state"
namespace: "windowing_frontend"
description: "Enables smarter closed device state state for foldable devices"
diff --git a/services/foldables/devicestateprovider/tests/src/com/android/server/policy/BookStyleDeviceStatePolicyTest.java b/services/foldables/devicestateprovider/tests/src/com/android/server/policy/BookStyleDeviceStatePolicyTest.java
index 2d725d1e2294..c25d5ef09209 100644
--- a/services/foldables/devicestateprovider/tests/src/com/android/server/policy/BookStyleDeviceStatePolicyTest.java
+++ b/services/foldables/devicestateprovider/tests/src/com/android/server/policy/BookStyleDeviceStatePolicyTest.java
@@ -45,6 +45,8 @@ import android.hardware.SensorManager;
import android.hardware.display.DisplayManager;
import android.hardware.input.InputSensorInfo;
import android.os.Handler;
+import android.os.PowerManager;
+import android.os.PowerManager.ScreenTimeoutPolicyListener;
import android.testing.AndroidTestingRunner;
import android.testing.TestableContext;
import android.view.Display;
@@ -98,6 +100,8 @@ public final class BookStyleDeviceStatePolicyTest {
@Mock
DisplayManager mDisplayManager;
@Mock
+ PowerManager mPowerManager;
+ @Mock
private Display mDisplay;
private final FakeFeatureFlagsImpl mFakeFeatureFlags = new FakeFeatureFlagsImpl();
@@ -118,6 +122,7 @@ public final class BookStyleDeviceStatePolicyTest {
private Map<Sensor, List<SensorEventListener>> mSensorEventListeners = new HashMap<>();
private DeviceStateProvider mProvider;
+ private BookStyleDeviceStatePolicy mPolicy;
@Before
public void setup() {
@@ -125,6 +130,7 @@ public final class BookStyleDeviceStatePolicyTest {
mFakeFeatureFlags.setFlag(Flags.FLAG_ENABLE_FOLDABLES_POSTURE_BASED_CLOSED_STATE, true);
mFakeFeatureFlags.setFlag(Flags.FLAG_ENABLE_DUAL_DISPLAY_BLOCKING, true);
+ mFakeFeatureFlags.setFlag(Flags.FLAG_FORCE_FOLDABLES_TENT_MODE_WITH_SCREEN_WAKELOCK, true);
when(mInputSensorInfo.getName()).thenReturn("hall-effect");
mHallSensor = new Sensor(mInputSensorInfo);
@@ -146,6 +152,7 @@ public final class BookStyleDeviceStatePolicyTest {
when(mDisplayManager.getDisplay(eq(DEFAULT_DISPLAY))).thenReturn(mDisplay);
mContext.addMockSystemService(DisplayManager.class, mDisplayManager);
+ mContext.addMockSystemService(PowerManager.class, mPowerManager);
mContext.ensureTestableResources();
when(mContext.getResources().getConfiguration()).thenReturn(mConfiguration);
@@ -592,6 +599,62 @@ public final class BookStyleDeviceStatePolicyTest {
}
@Test
+ public void test_unfoldTo85Degrees_screenWakeLockExists_forceTentModeWithWakeLockEnabled()
+ throws Exception {
+ mFakeFeatureFlags.setFlag(Flags.FLAG_FORCE_FOLDABLES_TENT_MODE_WITH_SCREEN_WAKELOCK, true);
+ mInstrumentation.runOnMainSync(() -> mProvider = createProvider());
+ mPolicy.getDeviceStateProvider().onSystemReady();
+ sendHingeAngle(0f);
+ final ScreenTimeoutPolicyListener listener = captureScreenTimeoutPolicyListener();
+ listener.onScreenTimeoutPolicyChanged(PowerManager.SCREEN_TIMEOUT_KEEP_DISPLAY_ON);
+ mProvider.setListener(mListener);
+ assertLatestReportedState(DEVICE_STATE_CLOSED);
+ sendHingeAngle(180f);
+ assertLatestReportedState(DEVICE_STATE_OPENED);
+ sendHingeAngle(0f);
+ sendHingeAngle(15f);
+ assertLatestReportedState(DEVICE_STATE_CLOSED);
+
+ sendHingeAngle(85f);
+
+ // Keeps 'closed' state meaning that it is in 'tent' mode as we have a screen wakelock
+ assertLatestReportedState(DEVICE_STATE_CLOSED);
+ }
+
+ @Test
+ public void test_unfoldTo85Degrees_noScreenWakelock_forceTentModeWithWakeLockEnabled()
+ throws Exception {
+ mFakeFeatureFlags.setFlag(Flags.FLAG_FORCE_FOLDABLES_TENT_MODE_WITH_SCREEN_WAKELOCK, true);
+ mInstrumentation.runOnMainSync(() -> mProvider = createProvider());
+ mPolicy.getDeviceStateProvider().onSystemReady();
+ sendHingeAngle(0f);
+ final ScreenTimeoutPolicyListener listener = captureScreenTimeoutPolicyListener();
+ listener.onScreenTimeoutPolicyChanged(PowerManager.SCREEN_TIMEOUT_ACTIVE);
+ mProvider.setListener(mListener);
+ assertLatestReportedState(DEVICE_STATE_CLOSED);
+ sendHingeAngle(180f);
+ assertLatestReportedState(DEVICE_STATE_OPENED);
+ sendHingeAngle(0f);
+ assertLatestReportedState(DEVICE_STATE_CLOSED);
+
+ sendHingeAngle(85f);
+
+ // Switches to half-opened state as we don't have a screen wakelock
+ assertLatestReportedState(DEVICE_STATE_HALF_OPENED);
+ }
+
+ @Test
+ public void test_unfoldTo85Degrees_notSubscribedToWakeLocks_forceTentModeWithWakeLockDisabled()
+ throws Exception {
+ mFakeFeatureFlags.setFlag(Flags.FLAG_FORCE_FOLDABLES_TENT_MODE_WITH_SCREEN_WAKELOCK, false);
+ mInstrumentation.runOnMainSync(() -> mProvider = createProvider());
+
+ mPolicy.getDeviceStateProvider().onSystemReady();
+
+ verify(mPowerManager, never()).addScreenTimeoutPolicyListener(anyInt(), any(), any());
+ }
+
+ @Test
public void test_foldTo10_leftSideIsFlat_keepsInnerScreenForReverseWedge() {
sendHingeAngle(180f);
sendLeftSideFlatSensorEvent(true);
@@ -751,8 +814,17 @@ public final class BookStyleDeviceStatePolicyTest {
}
private DeviceStateProvider createProvider() {
- return new BookStyleDeviceStatePolicy(mFakeFeatureFlags, mContext, mHingeAngleSensor,
+ mPolicy = new BookStyleDeviceStatePolicy(mFakeFeatureFlags, mContext, mHingeAngleSensor,
mHallSensor, mLeftAccelerometer, mRightAccelerometer,
- /* closeAngleDegrees= */ null).getDeviceStateProvider();
+ /* closeAngleDegrees= */ null);
+ return mPolicy.getDeviceStateProvider();
+ }
+
+ private ScreenTimeoutPolicyListener captureScreenTimeoutPolicyListener() {
+ final ArgumentCaptor<ScreenTimeoutPolicyListener> captor = ArgumentCaptor
+ .forClass(ScreenTimeoutPolicyListener.class);
+ verify(mPowerManager, atLeastOnce())
+ .addScreenTimeoutPolicyListener(anyInt(), any(), captor.capture());
+ return captor.getValue();
}
}
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index a8e6f689b424..dae481a3c215 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -1999,9 +1999,9 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_
// Create new lib file without signature info
incfs::NewFileParams libFileParams = {
.size = entry.uncompressed_length,
- .signature = {},
// Metadata of the new lib file is its relative path
.metadata = {targetLibPath.c_str(), (IncFsSize)targetLibPath.size()},
+ .signature = {},
};
incfs::FileId libFileId = idFromMetadata(targetLibPath);
if (auto res = mIncFs->makeFile(ifs->control, targetLibPathAbsolute, 0755, libFileId,
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
index 8ce2422563a3..70eeae648dd0 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
@@ -50,6 +50,7 @@ import android.view.inputmethod.InputMethodManager;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.annotations.GuardedBy;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import org.junit.Before;
@@ -74,6 +75,11 @@ public class ImeVisibilityStateComputerTest extends InputMethodManagerServiceTes
super.setUp();
ImeVisibilityStateComputer.Injector injector = new ImeVisibilityStateComputer.Injector() {
@Override
+ public UserManagerInternal getUserManagerService() {
+ return mMockUserManagerInternal;
+ }
+
+ @Override
public WindowManagerInternal getWmService() {
return mMockWindowManagerInternal;
}
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 b984624b3e9b..6adb01ccf11f 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/UserDataRepositoryTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/UserDataRepositoryTest.java
@@ -23,6 +23,7 @@ import android.view.WindowManager;
import androidx.annotation.NonNull;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import org.junit.After;
@@ -49,6 +50,9 @@ public final class UserDataRepositoryTest {
private InputMethodManagerService mMockInputMethodManagerService;
@Mock
+ private UserManagerInternal mMockUserManagerInternal;
+
+ @Mock
private WindowManagerInternal mMockWindowManagerInternal;
@NonNull
@@ -70,6 +74,12 @@ public final class UserDataRepositoryTest {
new ImeVisibilityStateComputer.Injector() {
@NonNull
@Override
+ public UserManagerInternal getUserManagerService() {
+ return mMockUserManagerInternal;
+ }
+
+ @NonNull
+ @Override
public WindowManagerInternal getWmService() {
return mMockWindowManagerInternal;
}
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java
index 58e4b9177808..8f26bf32335a 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java
@@ -72,8 +72,6 @@ public class BroadcastHelperTest {
private static final String PACKAGE_CHANGED_TEST_PACKAGE_NAME = "testpackagename";
private static final String PACKAGE_CHANGED_TEST_MAIN_ACTIVITY =
PACKAGE_CHANGED_TEST_PACKAGE_NAME + ".MainActivity";
- private static final String PERMISSION_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED =
- "android.permission.INTERNAL_RECEIVE_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED";
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@@ -125,34 +123,23 @@ public class BroadcastHelperTest {
@RequiresFlagsEnabled(FLAG_REDUCE_BROADCASTS_FOR_COMPONENT_STATE_CHANGES)
@Test
- public void changeNonExportedComponent_sendPackageChangedBroadcastToSystem_withPermission()
+ public void changeNonExportedComponent_sendPackageChangedBroadcastToSystemAndApplicationItself()
throws Exception {
changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */,
new String[0] /* sharedPackages */);
- ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
- verify(mMockActivityManagerInternal).broadcastIntentWithCallback(
- captor.capture(), eq(null),
- eq(new String[]{PERMISSION_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED}),
- anyInt(), eq(null), eq(null), eq(null));
- Intent intent = captor.getValue();
- assertNotNull(intent);
- assertThat(intent.getPackage()).isEqualTo("android");
- }
+ ArgumentCaptor<Intent> captorIntent = ArgumentCaptor.forClass(Intent.class);
+ verify(mMockActivityManagerInternal, times(2)).broadcastIntentWithCallback(
+ captorIntent.capture(), eq(null), eq(null), anyInt(), eq(null), eq(null), eq(null));
+ List<Intent> intents = captorIntent.getAllValues();
+ assertNotNull(intents);
+ assertThat(intents.size()).isEqualTo(2);
- @RequiresFlagsEnabled(FLAG_REDUCE_BROADCASTS_FOR_COMPONENT_STATE_CHANGES)
- @Test
- public void changeNonExportedComponent_sendPackageChangedBroadcastToApplicationItself()
- throws Exception {
- changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */,
- new String[0] /* sharedPackages */);
+ final Intent intent1 = intents.get(0);
+ assertThat(intent1.getPackage()).isEqualTo("android");
- ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
- verify(mMockActivityManagerInternal).broadcastIntentWithCallback(captor.capture(), eq(null),
- eq(null), anyInt(), eq(null), eq(null), eq(null));
- Intent intent = captor.getValue();
- assertNotNull(intent);
- assertThat(intent.getPackage()).isEqualTo(PACKAGE_CHANGED_TEST_PACKAGE_NAME);
+ final Intent intent2 = intents.get(1);
+ assertThat(intent2.getPackage()).isEqualTo(PACKAGE_CHANGED_TEST_PACKAGE_NAME);
}
@RequiresFlagsEnabled(FLAG_REDUCE_BROADCASTS_FOR_COMPONENT_STATE_CHANGES)
@@ -163,31 +150,20 @@ public class BroadcastHelperTest {
new String[]{"shared.package"} /* sharedPackages */);
ArgumentCaptor<Intent> captorIntent = ArgumentCaptor.forClass(Intent.class);
- ArgumentCaptor<String[]> captorRequiredPermissions = ArgumentCaptor.forClass(
- String[].class);
verify(mMockActivityManagerInternal, times(3)).broadcastIntentWithCallback(
- captorIntent.capture(), eq(null), captorRequiredPermissions.capture(), anyInt(),
- eq(null), eq(null), eq(null));
+ captorIntent.capture(), eq(null), eq(null), anyInt(), eq(null), eq(null), eq(null));
List<Intent> intents = captorIntent.getAllValues();
- List<String[]> requiredPermissions = captorRequiredPermissions.getAllValues();
assertNotNull(intents);
assertThat(intents.size()).isEqualTo(3);
final Intent intent1 = intents.get(0);
- final String[] requiredPermission1 = requiredPermissions.get(0);
assertThat(intent1.getPackage()).isEqualTo("android");
- assertThat(requiredPermission1).isEqualTo(
- new String[]{PERMISSION_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED});
final Intent intent2 = intents.get(1);
- final String[] requiredPermission2 = requiredPermissions.get(1);
assertThat(intent2.getPackage()).isEqualTo(PACKAGE_CHANGED_TEST_PACKAGE_NAME);
- assertThat(requiredPermission2).isNull();
final Intent intent3 = intents.get(2);
- final String[] requiredPermission3 = requiredPermissions.get(2);
assertThat(intent3.getPackage()).isEqualTo("shared.package");
- assertThat(requiredPermission3).isNull();
}
@Test
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
index f5bed999d5a0..5393e20889c0 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -455,8 +455,9 @@ public class LocalDisplayAdapterTest {
* Confirm that external display uses physical density.
*/
@Test
- public void testDpiValues() throws Exception {
+ public void testDpiValues_baseDensityForExternalDisplaysDisabled() throws Exception {
// needs default one always
+ doReturn(false).when(mFlags).isBaseDensityForExternalDisplaysEnabled();
setUpDisplay(new FakeDisplay(PORT_A));
setUpDisplay(new FakeDisplay(PORT_B));
updateAvailableDisplays();
@@ -472,6 +473,25 @@ public class LocalDisplayAdapterTest {
16000);
}
+ @Test
+ public void testDpiValues_baseDensityForExternalDisplaysEnabled() throws Exception {
+ // needs default one always
+ doReturn(true).when(mFlags).isBaseDensityForExternalDisplaysEnabled();
+ setUpDisplay(new FakeDisplay(PORT_A));
+ setUpDisplay(new FakeDisplay(PORT_B));
+ updateAvailableDisplays();
+ mAdapter.registerLocked();
+
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+ assertDisplayDpi(
+ mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked(), PORT_A, 100, 100,
+ 100);
+ assertDisplayDpi(
+ mListener.addedDisplays.get(1).getDisplayDeviceInfoLocked(), PORT_B, 100, 100,
+ 100);
+ }
+
private static class DisplayModeWrapper {
public SurfaceControl.DisplayMode mode;
public float[] expectedAlternativeRefreshRates;
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/fudger/LocationFudgerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/fudger/LocationFudgerTest.java
index f442eb69594e..ebaa2e84c044 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/fudger/LocationFudgerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/fudger/LocationFudgerTest.java
@@ -271,4 +271,31 @@ public class LocationFudgerTest {
assertThat(center[0]).isEqualTo(expected[0]);
assertThat(center[1]).isEqualTo(expected[1]);
}
+
+ @Test
+ public void getS2CellApproximateEdge_returnsCorrectRadius() {
+ int level = 10;
+
+ float radius = mFudger.getS2CellApproximateEdge(level);
+
+ assertThat(radius).isEqualTo(9000); // in meters
+ }
+
+ @Test
+ public void getS2CellApproximateEdge_doesNotThrow() {
+ int level = -1;
+
+ mFudger.getS2CellApproximateEdge(level);
+
+ // No exception thrown.
+ }
+
+ @Test
+ public void getS2CellApproximateEdge_doesNotThrow2() {
+ int level = 14;
+
+ mFudger.getS2CellApproximateEdge(level);
+
+ // No exception thrown.
+ }
}
diff --git a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
index d9256247b835..6b138b986fe7 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -27,6 +27,7 @@ import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
+import static android.service.dreams.Flags.FLAG_ALLOW_DREAM_WHEN_POSTURED;
import static com.android.server.deviceidle.Flags.FLAG_DISABLE_WAKELOCKS_IN_LIGHT_IDLE;
@@ -81,8 +82,8 @@ import android.os.BatterySaverPolicyConfig;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
-import android.os.IWakeLockCallback;
import android.os.IScreenTimeoutPolicyListener;
+import android.os.IWakeLockCallback;
import android.os.Looper;
import android.os.PowerManager;
import android.os.PowerManagerInternal;
@@ -120,8 +121,8 @@ import com.android.server.power.PowerManagerService.WakeLock;
import com.android.server.power.batterysaver.BatterySaverController;
import com.android.server.power.batterysaver.BatterySaverPolicy;
import com.android.server.power.batterysaver.BatterySaverStateMachine;
-import com.android.server.power.feature.flags.Flags;
import com.android.server.power.feature.PowerManagerFlags;
+import com.android.server.power.feature.flags.Flags;
import com.android.server.testutils.OffsettableClock;
import com.google.testing.junit.testparameterinjector.TestParameter;
@@ -279,6 +280,8 @@ public class PowerManagerServiceTest {
Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
Settings.Secure.putInt(mContextSpy.getContentResolver(),
Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 0);
+ Settings.Secure.putInt(mContextSpy.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED, 0);
mClock = new OffsettableClock.Stopped();
mTestLooper = new TestLooper(mClock::now);
@@ -1215,6 +1218,52 @@ public class PowerManagerServiceTest {
assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
}
+ @EnableFlags(FLAG_ALLOW_DREAM_WHEN_POSTURED)
+ @Test
+ public void testDreamActivateWhilePosturedEnabled_postured_afterTimeout_goesToDreaming() {
+ when(mBatteryManagerInternalMock.isPowered(anyInt())).thenReturn(true);
+ Settings.Secure.putInt(mContextSpy.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED, 1);
+
+ doAnswer(inv -> {
+ when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+ return null;
+ }).when(mDreamManagerInternalMock).startDream(anyBoolean(), anyString());
+
+ setMinimumScreenOffTimeoutConfig(5);
+ createService();
+ startSystem();
+ mService.getLocalServiceInstance().setDevicePostured(true);
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ advanceTime(15000);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+ }
+
+ @EnableFlags(FLAG_ALLOW_DREAM_WHEN_POSTURED)
+ @Test
+ public void testDreamActivateWhilePosturedEnabled_notPostured_afterTimeout_goesToDozing() {
+ when(mBatteryManagerInternalMock.isPowered(anyInt())).thenReturn(true);
+ Settings.Secure.putInt(mContextSpy.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED, 1);
+
+ doAnswer(inv -> {
+ when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+ return null;
+ }).when(mDreamManagerInternalMock).startDream(anyBoolean(), anyString());
+
+ setMinimumScreenOffTimeoutConfig(5);
+ createService();
+ startSystem();
+ mService.getLocalServiceInstance().setDevicePostured(false);
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ advanceTime(15000);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+ }
+
@EnableFlags(android.companion.virtualdevice.flags.Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER)
@SuppressWarnings("GuardedBy")
@Test
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryChargeCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryChargeCalculatorTest.java
index 9b45ca79fdab..ec8ede06099f 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryChargeCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryChargeCalculatorTest.java
@@ -51,6 +51,7 @@ public class BatteryChargeCalculatorTest {
@Before
public void setup() {
+ mStatsRule.getBatteryStats().setNoAutoReset(true);
mStatsRule.getBatteryStats().onSystemReady(mock(Context.class));
}
@@ -83,8 +84,8 @@ public class BatteryChargeCalculatorTest {
.isWithin(PRECISION).of(360.0);
assertThat(batteryUsageStats.getDischargedPowerRange().getUpper())
.isWithin(PRECISION).of(400.0);
- // 5_000_000 (current time) - 1_000_000 (started discharging)
- assertThat(batteryUsageStats.getDischargeDurationMs()).isEqualTo(4_000_000);
+ // 5_000_000 (current time) - 0 (started discharging, see BatteryUsageStatsRule)
+ assertThat(batteryUsageStats.getDischargeDurationMs()).isEqualTo(5_000_000);
assertThat(batteryUsageStats.getBatteryTimeRemainingMs()).isEqualTo(8_000_000);
assertThat(batteryUsageStats.getChargeTimeRemainingMs()).isEqualTo(-1);
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java
index d83dc110800a..db3268729f1e 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java
@@ -141,8 +141,7 @@ public class BatteryStatsImplTest {
HandlerThread bgThread = new HandlerThread("bg thread");
bgThread.start();
mHandler = new Handler(bgThread.getLooper());
- mBatteryStatsImpl = new MockBatteryStatsImpl(mMockClock, null, mHandler)
- .setPowerProfile(mPowerProfile)
+ mBatteryStatsImpl = new MockBatteryStatsImpl(mMockClock, null, mHandler, mPowerProfile)
.setCpuScalingPolicies(mCpuScalingPolicies)
.setKernelCpuUidFreqTimeReader(mKernelUidCpuFreqTimeReader)
.setKernelSingleUidTimeReader(mKernelSingleUidTimeReader)
@@ -919,11 +918,11 @@ public class BatteryStatsImplTest {
synchronized (mBatteryStatsImpl) {
mBatteryStatsImpl.setOnBatteryLocked(mMockClock.realtime, mMockClock.uptime, true,
BatteryManager.BATTERY_STATUS_DISCHARGING, 50, 0);
- // Will not save to PowerStatsStore because "saveBatteryUsageStatsOnReset" has not
- // been called yet.
- mBatteryStatsImpl.resetAllStatsAndHistoryLocked(
- BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
}
+ // Will not save to PowerStatsStore because "saveBatteryUsageStatsOnReset" has not
+ // been called yet.
+ mBatteryStatsImpl.startNewSession(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ awaitCompletion();
assertThat(mPowerStatsStore.getTableOfContents()).isEmpty();
@@ -945,15 +944,8 @@ public class BatteryStatsImplTest {
mMockClock.currentTime += 60000;
// Battery stats reset should have the side-effect of saving accumulated battery usage stats
- synchronized (mBatteryStatsImpl) {
- mBatteryStatsImpl.resetAllStatsAndHistoryLocked(
- BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
- }
-
- // Await completion
- ConditionVariable done = new ConditionVariable();
- mHandler.post(done::open);
- done.block();
+ mBatteryStatsImpl.startNewSession(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ awaitCompletion();
List<PowerStatsSpan.Metadata> contents = mPowerStatsStore.getTableOfContents();
assertThat(contents).hasSize(1);
@@ -982,4 +974,11 @@ public class BatteryStatsImplTest {
span.close();
}
+
+ private void awaitCompletion() {
+ // Await completion
+ ConditionVariable done = new ConditionVariable();
+ mHandler.post(done::open);
+ done.block();
+ }
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java
index 69579d6cb7d8..30ff8005563a 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java
@@ -32,7 +32,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
import android.app.ActivityManager;
import android.app.usage.NetworkStatsManager;
@@ -67,7 +66,6 @@ import androidx.test.filters.SmallTest;
import com.android.internal.os.BatteryStatsHistoryIterator;
import com.android.internal.os.MonotonicClock;
-import com.android.internal.os.PowerProfile;
import com.android.internal.power.EnergyConsumerStats;
import com.android.server.power.optimization.Flags;
import com.android.server.power.stats.BatteryStatsImpl.DualTimer;
@@ -1538,7 +1536,6 @@ public class BatteryStatsNoteTest {
public void testGetPerStateActiveRadioDurationMs_initialModemActivity() {
final MockClock clock = new MockClock(); // holds realtime and uptime in ms
final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clock);
- bi.setPowerProfile(mock(PowerProfile.class));
final int ratCount = RADIO_ACCESS_TECHNOLOGY_COUNT;
final int frequencyCount = ServiceState.FREQUENCY_RANGE_MMWAVE + 1;
@@ -1680,7 +1677,6 @@ public class BatteryStatsNoteTest {
public void testGetPerStateActiveRadioDurationMs_withModemActivity() {
final MockClock clock = new MockClock(); // holds realtime and uptime in ms
final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clock);
- bi.setPowerProfile(mock(PowerProfile.class));
final int ratCount = RADIO_ACCESS_TECHNOLOGY_COUNT;
final int frequencyCount = ServiceState.FREQUENCY_RANGE_MMWAVE + 1;
final int txLevelCount = CellSignalStrength.getNumSignalStrengthLevels();
@@ -1920,7 +1916,6 @@ public class BatteryStatsNoteTest {
public void testGetPerStateActiveRadioDurationMs_withSpecificInfoModemActivity() {
final MockClock clock = new MockClock(); // holds realtime and uptime in ms
final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clock);
- bi.setPowerProfile(mock(PowerProfile.class));
final int ratCount = RADIO_ACCESS_TECHNOLOGY_COUNT;
final int frequencyCount = ServiceState.FREQUENCY_RANGE_MMWAVE + 1;
final int txLevelCount = CellSignalStrength.getNumSignalStrengthLevels();
@@ -2313,7 +2308,6 @@ public class BatteryStatsNoteTest {
boolean update;
final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
- bi.setPowerProfile(mock(PowerProfile.class));
final int txLevelCount = CellSignalStrength.getNumSignalStrengthLevels();
final ModemActivityInfo mai = new ModemActivityInfo(0L, 0L, 0L, new int[txLevelCount], 0L);
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java
index 3635e9a749e2..b6d49d0ade0a 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java
@@ -34,7 +34,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.IOException;
-import java.nio.file.Files;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -45,13 +44,17 @@ public class BatteryStatsResetTest {
.setProvideMainThread(true)
.build();
+ @Rule(order = 1)
+ public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+ .createTempDirectory();
+
private static final int BATTERY_NOMINAL_VOLTAGE_MV = 3700;
private static final int BATTERY_CAPACITY_UAH = 4_000_000;
private static final int BATTERY_CHARGE_RATE_SECONDS_PER_LEVEL = 100;
private MockClock mMockClock;
- private BatteryStatsImpl.BatteryStatsConfig mConfig;
private MockBatteryStatsImpl mBatteryStatsImpl;
+ private BatteryStatsImpl.BatteryStatsConfig mConfig;
/**
* Battery status. Must be one of the following:
@@ -92,10 +95,9 @@ public class BatteryStatsResetTest {
@Before
public void setUp() throws IOException {
- mConfig = mock(BatteryStatsImpl.BatteryStatsConfig.class);
- mMockClock = new MockClock();
- mBatteryStatsImpl = new MockBatteryStatsImpl(mConfig, mMockClock,
- Files.createTempDirectory("BatteryStatsResetTest").toFile());
+ mMockClock = mStatsRule.getMockClock();
+ mConfig = mStatsRule.getBatteryStatsConfig();
+ mBatteryStatsImpl = mStatsRule.getBatteryStats();
mBatteryStatsImpl.onSystemReady(mock(Context.class));
// Set up the battery state. Start off with a fully charged plugged in battery.
@@ -112,6 +114,21 @@ public class BatteryStatsResetTest {
@Test
public void testResetOnUnplug_highBatteryLevel() {
+ mBatteryStatsImpl.resetBatteryHistoryOnNewSession(false);
+ long initialStartTime = mBatteryStatsImpl.getHistory().getStartTime();
+ resetOnUnplug_highBatteryLevel();
+ assertThat(mBatteryStatsImpl.getHistory().getStartTime()).isEqualTo(initialStartTime);
+ }
+
+ @Test
+ public void testResetOnUnplug_highBatteryLevel_resetHistory() {
+ mBatteryStatsImpl.resetBatteryHistoryOnNewSession(true);
+ resetOnUnplug_highBatteryLevel();
+ assertThat(mBatteryStatsImpl.getHistory().getStartTime())
+ .isEqualTo(mBatteryStatsImpl.getMonotonicStartTime());
+ }
+
+ private void resetOnUnplug_highBatteryLevel() {
when(mConfig.shouldResetOnUnplugHighBatteryLevel()).thenReturn(true);
long expectedResetTimeUs = 0;
@@ -149,6 +166,21 @@ public class BatteryStatsResetTest {
@Test
public void testResetOnUnplug_significantCharge() {
+ mBatteryStatsImpl.resetBatteryHistoryOnNewSession(false);
+ long initialStartTime = mBatteryStatsImpl.getHistory().getStartTime();
+ resetOnUnplug_significantCharge();
+ assertThat(mBatteryStatsImpl.getHistory().getStartTime()).isEqualTo(initialStartTime);
+ }
+
+ @Test
+ public void testResetOnUnplug_significantCharge_resetHistory() {
+ mBatteryStatsImpl.resetBatteryHistoryOnNewSession(true);
+ resetOnUnplug_significantCharge();
+ assertThat(mBatteryStatsImpl.getHistory().getStartTime())
+ .isEqualTo(mBatteryStatsImpl.getMonotonicStartTime());
+ }
+
+ private void resetOnUnplug_significantCharge() {
when(mConfig.shouldResetOnUnplugAfterSignificantCharge()).thenReturn(true);
long expectedResetTimeUs = 0;
@@ -244,7 +276,7 @@ public class BatteryStatsResetTest {
}
@Test
- public void testResetWhilePluggedIn_longPlugIn() {
+ public void testResetWhilePluggedIn_longPlugIn() throws Throwable {
// disable high battery level reset on unplug.
when(mConfig.shouldResetOnUnplugHighBatteryLevel()).thenReturn(false);
when(mConfig.shouldResetOnUnplugAfterSignificantCharge()).thenReturn(false);
@@ -253,18 +285,22 @@ public class BatteryStatsResetTest {
plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
- // Reset should not occur
+ mStatsRule.waitForBackgroundThread();
+ // Reset should not have occurred
assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
// Increment time a day
incTimeMs(24L * 60L * 60L * 1000L);
mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
+
// Reset should still not occur
assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
// Increment time a day
incTimeMs(24L * 60L * 60L * 1000L);
mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
+ mStatsRule.waitForBackgroundThread();
+
// Reset 47 hour threshold crossed, reset should occur.
expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000;
assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
@@ -272,12 +308,14 @@ public class BatteryStatsResetTest {
// Increment time a day
incTimeMs(24L * 60L * 60L * 1000L);
mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
+ mStatsRule.waitForBackgroundThread();
// Reset should not occur
assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
// Increment time a day
incTimeMs(24L * 60L * 60L * 1000L);
mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
+ mStatsRule.waitForBackgroundThread();
// Reset another 47 hour threshold crossed, reset should occur.
expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000;
assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
@@ -285,6 +323,7 @@ public class BatteryStatsResetTest {
// Increment time a day
incTimeMs(24L * 60L * 60L * 1000L);
mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
+ mStatsRule.waitForBackgroundThread();
// Reset should not occur
assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
@@ -294,12 +333,14 @@ public class BatteryStatsResetTest {
// Increment time a day
incTimeMs(24L * 60L * 60L * 1000L);
mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
+ mStatsRule.waitForBackgroundThread();
// Reset should not occur, since unplug occurred recently.
assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
// Increment time a day
incTimeMs(24L * 60L * 60L * 1000L);
mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
+ mStatsRule.waitForBackgroundThread();
// Reset another 47 hour threshold crossed, reset should occur.
expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000;
assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
@@ -353,5 +394,10 @@ public class BatteryStatsResetTest {
mBatteryChargeFullUah, mBatteryChargeTimeToFullSeconds,
mMockClock.elapsedRealtime(), mMockClock.uptimeMillis(),
mMockClock.currentTimeMillis());
+ try {
+ mStatsRule.waitForBackgroundThread();
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
}
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
index 73dcfe77e67f..d427c9d9ee37 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
@@ -35,7 +35,6 @@ import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
-import android.os.ConditionVariable;
import android.os.Handler;
import android.os.Parcel;
import android.os.Process;
@@ -180,6 +179,7 @@ public class BatteryUsageStatsProviderTest {
private BatteryStatsImpl prepareBatteryStats(boolean plugInAtTheEnd) {
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
+ batteryStats.setNoAutoReset(true);
batteryStats.onSystemReady(mContext);
synchronized (batteryStats) {
@@ -481,13 +481,12 @@ public class BatteryUsageStatsProviderTest {
}
@Test
- public void testAggregateBatteryStats() throws IOException {
+ public void testAggregateBatteryStats() throws Throwable {
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
setTime(5 * MINUTE_IN_MS);
- synchronized (batteryStats) {
- batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
- }
+ batteryStats.startNewSession(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ mStatsRule.waitForBackgroundThread();
PowerStatsStore powerStatsStore = new PowerStatsStore(
new File(mStatsRule.getHistoryDir(), "powerstatsstore"),
@@ -501,9 +500,8 @@ public class BatteryUsageStatsProviderTest {
batteryStats.saveBatteryUsageStatsOnReset(provider, powerStatsStore,
/* accumulateBatteryUsageStats */ false);
- synchronized (batteryStats) {
- batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
- }
+ batteryStats.startNewSession(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ mStatsRule.waitForBackgroundThread();
synchronized (batteryStats) {
batteryStats.noteFlashlightOnLocked(APP_UID,
@@ -514,9 +512,8 @@ public class BatteryUsageStatsProviderTest {
20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS);
}
setTime(25 * MINUTE_IN_MS);
- synchronized (batteryStats) {
- batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
- }
+ batteryStats.startNewSession(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ mStatsRule.waitForBackgroundThread();
synchronized (batteryStats) {
batteryStats.noteFlashlightOnLocked(APP_UID,
@@ -527,9 +524,8 @@ public class BatteryUsageStatsProviderTest {
50 * MINUTE_IN_MS, 50 * MINUTE_IN_MS);
}
setTime(55 * MINUTE_IN_MS);
- synchronized (batteryStats) {
- batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
- }
+ batteryStats.startNewSession(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ mStatsRule.waitForBackgroundThread();
// This section should be ignored because the timestamp is out or range
synchronized (batteryStats) {
@@ -541,9 +537,8 @@ public class BatteryUsageStatsProviderTest {
70 * MINUTE_IN_MS, 70 * MINUTE_IN_MS);
}
setTime(75 * MINUTE_IN_MS);
- synchronized (batteryStats) {
- batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
- }
+ batteryStats.startNewSession(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ mStatsRule.waitForBackgroundThread();
// This section should be ignored because it represents the current stats session
synchronized (batteryStats) {
@@ -556,10 +551,7 @@ public class BatteryUsageStatsProviderTest {
}
setTime(95 * MINUTE_IN_MS);
- // Await completion
- ConditionVariable done = new ConditionVariable();
- mStatsRule.getHandler().post(done::open);
- done.block();
+ mStatsRule.waitForBackgroundThread();
// Include the first and the second snapshot, but not the third or current
BatteryUsageStatsQuery query = new BatteryUsageStatsQuery.Builder()
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
index 9e7e0b646047..53a2522d299e 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
@@ -86,6 +86,7 @@ public class BatteryUsageStatsRule implements TestRule {
private String[] mCustomPowerComponentNames;
private Throwable mThrowable;
private final BatteryStatsImpl.BatteryStatsConfig.Builder mBatteryStatsConfigBuilder;
+ private BatteryStatsImpl.BatteryStatsConfig mBatteryStatsConfig;
public BatteryUsageStatsRule() {
this(0);
@@ -119,9 +120,8 @@ public class BatteryUsageStatsRule implements TestRule {
}
clearDirectory();
}
- mBatteryStats = new MockBatteryStatsImpl(mBatteryStatsConfigBuilder.build(),
- mMockClock, mMonotonicClock, mHistoryDir, mHandler, new PowerStatsUidResolver());
- mBatteryStats.setPowerProfile(mPowerProfile);
+ mBatteryStats = new MockBatteryStatsImpl(getBatteryStatsConfig(), mMockClock,
+ mMonotonicClock, mHistoryDir, mHandler, mPowerProfile, new PowerStatsUidResolver());
mBatteryStats.setCpuScalingPolicies(new CpuScalingPolicies(mCpusByPolicy, mFreqsByPolicy));
synchronized (mBatteryStats) {
mBatteryStats.initEnergyConsumerStatsLocked(mSupportedStandardBuckets,
@@ -142,6 +142,17 @@ public class BatteryUsageStatsRule implements TestRule {
}
}
+ /**
+ * Returns the BatteryStatsConfig, which is wrapped into a Mockito.spy, so it can be
+ * observed and/or mocked.
+ */
+ public BatteryStatsImpl.BatteryStatsConfig getBatteryStatsConfig() {
+ if (mBatteryStatsConfig == null) {
+ mBatteryStatsConfig = spy(mBatteryStatsConfigBuilder.build());
+ }
+ return mBatteryStatsConfig;
+ }
+
public MockClock getMockClock() {
return mMockClock;
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
index 8a081f8e16cc..a69e2fdb0b03 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
@@ -65,29 +65,27 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
}
MockBatteryStatsImpl(Clock clock, File historyDirectory) {
- this(clock, historyDirectory, new Handler(Looper.getMainLooper()));
+ this(clock, historyDirectory, new Handler(Looper.getMainLooper()), mockPowerProfile());
}
- MockBatteryStatsImpl(Clock clock, File historyDirectory, Handler handler) {
- this(DEFAULT_CONFIG, clock, historyDirectory, handler, new PowerStatsUidResolver());
+ MockBatteryStatsImpl(Clock clock, File historyDirectory, Handler handler,
+ PowerProfile powerProfile) {
+ this(DEFAULT_CONFIG, clock, new MonotonicClock(0, clock), historyDirectory, handler,
+ powerProfile, new PowerStatsUidResolver());
}
- MockBatteryStatsImpl(BatteryStatsConfig config, Clock clock, File historyDirectory) {
- this(config, clock, historyDirectory, new Handler(Looper.getMainLooper()),
- new PowerStatsUidResolver());
- }
-
- MockBatteryStatsImpl(BatteryStatsConfig config, Clock clock,
- File historyDirectory, Handler handler, PowerStatsUidResolver powerStatsUidResolver) {
+ MockBatteryStatsImpl(BatteryStatsConfig config, Clock clock, File historyDirectory,
+ Handler handler, PowerStatsUidResolver powerStatsUidResolver) {
this(config, clock, new MonotonicClock(0, clock), historyDirectory, handler,
- powerStatsUidResolver);
+ mockPowerProfile(), powerStatsUidResolver);
}
MockBatteryStatsImpl(BatteryStatsConfig config, Clock clock, MonotonicClock monotonicClock,
- File historyDirectory, Handler handler, PowerStatsUidResolver powerStatsUidResolver) {
+ File historyDirectory, Handler handler, PowerProfile powerProfile,
+ PowerStatsUidResolver powerStatsUidResolver) {
super(config, clock, monotonicClock, historyDirectory, handler,
mock(PlatformIdleStateCallback.class), mock(EnergyStatsRetriever.class),
- mock(UserInfoProvider.class), mockPowerProfile(),
+ mock(UserInfoProvider.class), powerProfile,
new CpuScalingPolicies(new SparseArray<>(), new SparseArray<>()),
powerStatsUidResolver, mock(FrameworkStatsLogger.class),
mock(BatteryStatsHistory.TraceDelegate.class),
@@ -172,12 +170,6 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
return mNetworkStats;
}
- public MockBatteryStatsImpl setPowerProfile(PowerProfile powerProfile) {
- mPowerProfile = powerProfile;
- setTestCpuScalingPolicies();
- return this;
- }
-
public MockBatteryStatsImpl setTestCpuScalingPolicies() {
SparseArray<int[]> cpusByPolicy = new SparseArray<>();
cpusByPolicy.put(0, new int[]{0});
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/UserPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/UserPowerCalculatorTest.java
deleted file mode 100644
index 438f0ec36177..000000000000
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/UserPowerCalculatorTest.java
+++ /dev/null
@@ -1,165 +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 com.android.server.power.stats;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.os.BatteryConsumer;
-import android.os.BatteryStats;
-import android.os.BatteryUsageStatsQuery;
-import android.os.Process;
-import android.os.UidBatteryConsumer;
-import android.os.UserBatteryConsumer;
-import android.os.UserHandle;
-import android.platform.test.ravenwood.RavenwoodRule;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class UserPowerCalculatorTest {
- @Rule(order = 0)
- public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
- .setProvideMainThread(true)
- .build();
-
- public static final int USER1 = 0;
- public static final int USER2 = 1625;
-
- private static final int APP_UID1 = Process.FIRST_APPLICATION_UID + 42;
- private static final int APP_UID2 = Process.FIRST_APPLICATION_UID + 272;
- private static final int APP_UID3 = Process.FIRST_APPLICATION_UID + 314;
-
- @Rule(order = 1)
- public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule();
-
- @Test
- public void testAllUsers() {
- prepareUidBatteryConsumers();
-
- UserPowerCalculator calculator = new UserPowerCalculator();
-
- mStatsRule.apply(BatteryUsageStatsQuery.DEFAULT, calculator, new FakeAudioPowerCalculator(),
- new FakeVideoPowerCalculator());
-
- assertThat(mStatsRule.getUserBatteryConsumer(USER1)).isNull();
-
- assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID1))
- .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO)).isEqualTo(3000);
- assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID1))
- .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO)).isEqualTo(7000);
-
- assertThat(mStatsRule.getUserBatteryConsumer(USER2)).isNull();
-
- assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER2, APP_UID2))
- .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO)).isEqualTo(5555);
- assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER2, APP_UID2))
- .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO)).isEqualTo(9999);
- }
-
- @Test
- public void testSpecificUser() {
- prepareUidBatteryConsumers();
-
- UserPowerCalculator calculator = new UserPowerCalculator();
-
- mStatsRule.apply(new BatteryUsageStatsQuery.Builder().addUser(UserHandle.of(USER1)).build(),
- calculator, new FakeAudioPowerCalculator(), new FakeVideoPowerCalculator());
-
- assertThat(mStatsRule.getUserBatteryConsumer(USER1)).isNull();
-
- assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID1))
- .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO)).isEqualTo(3000);
- assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID1))
- .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO)).isEqualTo(7000);
- assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID2))).isNull();
- assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID3))
- .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO)).isEqualTo(7070);
- assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID3))
- .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO)).isEqualTo(11110);
-
- UserBatteryConsumer user2 = mStatsRule.getUserBatteryConsumer(USER2);
- assertThat(user2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO))
- .isEqualTo(15308);
- assertThat(user2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO))
- .isEqualTo(24196);
-
- assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER2, APP_UID1))).isNull();
- assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER2, APP_UID2))).isNull();
- assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER2, APP_UID3))).isNull();
- }
-
- private void prepareUidBatteryConsumers() {
- prepareUidBatteryConsumer(USER1, APP_UID1, 1000, 2000, 3000, 4000);
- prepareUidBatteryConsumer(USER2, APP_UID2, 2222, 3333, 4444, 5555);
- prepareUidBatteryConsumer(USER1, APP_UID3, 3030, 4040, 5050, 6060);
- prepareUidBatteryConsumer(USER2, APP_UID3, 4321, 5432, 6543, 7654);
- }
-
- private void prepareUidBatteryConsumer(int userId, int uid, long audioDuration1Ms,
- long audioDuration2Ms, long videoDuration1Ms, long videoDuration2Ms) {
- BatteryStatsImpl.Uid uidStats = mStatsRule.getUidStats(UserHandle.getUid(userId, uid));
-
- // Use "audio" and "video" to fake some power consumption. Could be any other type of usage.
- uidStats.noteAudioTurnedOnLocked(0);
- uidStats.noteAudioTurnedOffLocked(audioDuration1Ms);
- uidStats.noteAudioTurnedOnLocked(1000000);
- uidStats.noteAudioTurnedOffLocked(1000000 + audioDuration2Ms);
-
- uidStats.noteVideoTurnedOnLocked(0);
- uidStats.noteVideoTurnedOffLocked(videoDuration1Ms);
- uidStats.noteVideoTurnedOnLocked(2000000);
- uidStats.noteVideoTurnedOffLocked(2000000 + videoDuration2Ms);
- }
-
- private static class FakeAudioPowerCalculator extends PowerCalculator {
-
- @Override
- public boolean isPowerComponentSupported(
- @BatteryConsumer.PowerComponent int powerComponent) {
- return powerComponent == BatteryConsumer.POWER_COMPONENT_AUDIO;
- }
-
- @Override
- protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
- long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
- long durationMs = u.getAudioTurnedOnTimer().getTotalTimeLocked(rawRealtimeUs, 0);
- app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO, durationMs / 1000);
- }
- }
-
- private static class FakeVideoPowerCalculator extends PowerCalculator {
-
- @Override
- public boolean isPowerComponentSupported(
- @BatteryConsumer.PowerComponent int powerComponent) {
- return powerComponent == BatteryConsumer.POWER_COMPONENT_VIDEO;
- }
-
- @Override
- protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
- long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
- long durationMs = u.getVideoTurnedOnTimer().getTotalTimeLocked(rawRealtimeUs, 0);
- app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO, durationMs / 1000);
- }
- }
-}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerStatsCollectorTest.java
index ed927c6ab699..d8059a6e1d2a 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerStatsCollectorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerStatsCollectorTest.java
@@ -80,6 +80,7 @@ public class WakelockPowerStatsCollectorTest {
POWER_COMPONENT_WAKELOCK);
mBatteryStats.forceRecordAllHistory();
+ mBatteryStats.setNoAutoReset(true);
mStatsRule.advanceSuspendedTime(1000);
diff --git a/services/tests/selinux/src/com/android/server/selinux/SelinuxAuditLogsCollectorTest.java b/services/tests/selinux/src/com/android/server/selinux/SelinuxAuditLogsCollectorTest.java
index db58c74e8431..29f55ff53e6e 100644
--- a/services/tests/selinux/src/com/android/server/selinux/SelinuxAuditLogsCollectorTest.java
+++ b/services/tests/selinux/src/com/android/server/selinux/SelinuxAuditLogsCollectorTest.java
@@ -20,6 +20,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -81,7 +82,7 @@ public class SelinuxAuditLogsCollectorTest {
}
@Test
- public void testWriteAuditLogs() {
+ public void testWriteAuditLogs() throws Exception {
writeTestLog("granted", "perm", TEST_DOMAIN, "ttype", "tclass");
writeTestLog("denied", "perm1", TEST_DOMAIN, "ttype1", "tclass1");
@@ -117,7 +118,7 @@ public class SelinuxAuditLogsCollectorTest {
}
@Test
- public void testWriteAuditLogs_multiplePerms() {
+ public void testWriteAuditLogs_multiplePerms() throws Exception {
writeTestLog("denied", "perm1 perm2", TEST_DOMAIN, "ttype", "tclass");
writeTestLog("denied", "perm3 perm4", TEST_DOMAIN, "ttype", "tclass");
@@ -153,7 +154,7 @@ public class SelinuxAuditLogsCollectorTest {
}
@Test
- public void testWriteAuditLogs_withPaths() {
+ public void testWriteAuditLogs_withPaths() throws Exception {
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass", "/good/path");
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass", "/very/long/path");
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass", "/short_path");
@@ -217,7 +218,7 @@ public class SelinuxAuditLogsCollectorTest {
}
@Test
- public void testWriteAuditLogs_withCategories() {
+ public void testWriteAuditLogs_withCategories() throws Exception {
writeTestLog("denied", "perm", TEST_DOMAIN, new int[] {123}, "ttype", null, "tclass");
writeTestLog("denied", "perm", TEST_DOMAIN, new int[] {123, 456}, "ttype", null, "tclass");
writeTestLog("denied", "perm", TEST_DOMAIN, null, "ttype", new int[] {666}, "tclass");
@@ -288,7 +289,7 @@ public class SelinuxAuditLogsCollectorTest {
}
@Test
- public void testWriteAuditLogs_withPathAndCategories() {
+ public void testWriteAuditLogs_withPathAndCategories() throws Exception {
writeTestLog(
"denied",
"perm",
@@ -318,7 +319,7 @@ public class SelinuxAuditLogsCollectorTest {
}
@Test
- public void testWriteAuditLogs_permissive() {
+ public void testWriteAuditLogs_permissive() throws Exception {
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass", true);
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass", false);
@@ -356,7 +357,7 @@ public class SelinuxAuditLogsCollectorTest {
}
@Test
- public void testNotWriteAuditLogs_notTestDomain() {
+ public void testNotWriteAuditLogs_notTestDomain() throws Exception {
writeTestLog("denied", "perm", "stype", "ttype", "tclass");
boolean done = mSelinuxAutidLogsCollector.collect(ANSWER_TAG);
@@ -379,7 +380,7 @@ public class SelinuxAuditLogsCollectorTest {
}
@Test
- public void testWriteAuditLogs_upToQuota() {
+ public void testWriteAuditLogs_upToQuota() throws Exception {
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
@@ -389,9 +390,9 @@ public class SelinuxAuditLogsCollectorTest {
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
- boolean done = mSelinuxAutidLogsCollector.collect(ANSWER_TAG);
+ assertThrows(QuotaExceededException.class, () ->
+ mSelinuxAutidLogsCollector.collect(ANSWER_TAG));
- assertThat(done).isTrue();
verify(
() ->
FrameworkStatsLog.write(
@@ -409,7 +410,7 @@ public class SelinuxAuditLogsCollectorTest {
}
@Test
- public void testWriteAuditLogs_resetQuota() {
+ public void testWriteAuditLogs_resetQuota() throws Exception {
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
@@ -418,8 +419,8 @@ public class SelinuxAuditLogsCollectorTest {
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
- boolean done = mSelinuxAutidLogsCollector.collect(ANSWER_TAG);
- assertThat(done).isTrue();
+ assertThrows(QuotaExceededException.class, () ->
+ mSelinuxAutidLogsCollector.collect(ANSWER_TAG));
verify(
() ->
FrameworkStatsLog.write(
@@ -442,8 +443,8 @@ public class SelinuxAuditLogsCollectorTest {
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
// move the clock forward to reset the quota limiter.
mClock.currentTimeMillis += Duration.ofHours(1).toMillis();
- done = mSelinuxAutidLogsCollector.collect(ANSWER_TAG);
- assertThat(done).isTrue();
+ assertThrows(QuotaExceededException.class, () ->
+ mSelinuxAutidLogsCollector.collect(ANSWER_TAG));
verify(
() ->
FrameworkStatsLog.write(
@@ -461,14 +462,11 @@ public class SelinuxAuditLogsCollectorTest {
}
@Test
- public void testNotWriteAuditLogs_stopRequested() {
- writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
+ public void testNotWriteAuditLogs_stopRequested() throws Exception {
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
- // These are not pushed.
- writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
mSelinuxAutidLogsCollector.setStopRequested(true);
@@ -509,7 +507,7 @@ public class SelinuxAuditLogsCollectorTest {
}
@Test
- public void testAuditLogs_resumeJobDoesNotExceedLimit() {
+ public void testAuditLogs_resumeJobDoesNotExceedLimit() throws Exception {
writeTestLog("denied", "perm", TEST_DOMAIN, "ttype", "tclass");
mSelinuxAutidLogsCollector.setStopRequested(true);
diff --git a/services/tests/selinux/src/com/android/server/selinux/SelinuxAuditLogsJobTest.java b/services/tests/selinux/src/com/android/server/selinux/SelinuxAuditLogsJobTest.java
index 2aea8a033f87..344f3295f682 100644
--- a/services/tests/selinux/src/com/android/server/selinux/SelinuxAuditLogsJobTest.java
+++ b/services/tests/selinux/src/com/android/server/selinux/SelinuxAuditLogsJobTest.java
@@ -53,7 +53,7 @@ public class SelinuxAuditLogsJobTest {
}
@Test
- public void testFinishSuccessfully() {
+ public void testFinishSuccessfully() throws Exception {
when(mAuditLogsCollector.collect(anyInt())).thenReturn(true);
mAuditLogsJob.start(mJobService, mParams);
@@ -63,7 +63,7 @@ public class SelinuxAuditLogsJobTest {
}
@Test
- public void testInterrupt() {
+ public void testInterrupt() throws Exception {
when(mAuditLogsCollector.collect(anyInt())).thenReturn(false);
mAuditLogsJob.start(mJobService, mParams);
@@ -73,7 +73,7 @@ public class SelinuxAuditLogsJobTest {
}
@Test
- public void testInterruptAndResume() {
+ public void testInterruptAndResume() throws Exception {
when(mAuditLogsCollector.collect(anyInt())).thenReturn(false);
mAuditLogsJob.start(mJobService, mParams);
verify(mJobService, never()).jobFinished(any(), anyBoolean());
@@ -85,7 +85,7 @@ public class SelinuxAuditLogsJobTest {
}
@Test
- public void testRequestStop() throws InterruptedException {
+ public void testRequestStop() throws Exception {
Semaphore isRunning = new Semaphore(0);
Semaphore stopRequested = new Semaphore(0);
AtomicReference<Throwable> uncaughtException = new AtomicReference<>();
diff --git a/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java b/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java
index cc5be7ebba62..1522954c123f 100644
--- a/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java
@@ -46,17 +46,14 @@ import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SystemProperties;
import android.provider.DeviceConfig;
-import android.util.Log;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
-import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.os.IBinaryTransparencyService;
-import com.android.server.pm.BackgroundInstallControlService;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.server.pm.BackgroundInstallControlCallbackHelper;
-import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.AndroidPackageSplit;
+import com.android.server.pm.BackgroundInstallControlService;
import com.android.server.pm.pkg.PackageStateInternal;
import org.junit.After;
@@ -82,7 +79,7 @@ public class BinaryTransparencyServiceTest {
private Context mContext;
private BinaryTransparencyService mBinaryTransparencyService;
private BinaryTransparencyService.BinaryTransparencyServiceImpl mTestInterface;
- private DeviceConfig.Properties mOriginalBiometricsFlags;
+ private String mOriginalBiometricsFlag;
@Mock
private BinaryTransparencyService.BiometricLogger mBiometricLogger;
@@ -117,17 +114,15 @@ public class BinaryTransparencyServiceTest {
mBinaryTransparencyService = new BinaryTransparencyService(mContext, mBiometricLogger);
mTestInterface = mBinaryTransparencyService.new BinaryTransparencyServiceImpl();
- mOriginalBiometricsFlags = DeviceConfig.getProperties(DeviceConfig.NAMESPACE_BIOMETRICS);
+ mOriginalBiometricsFlag = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_BIOMETRICS,
+ BinaryTransparencyService.KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION);
}
@After
- public void tearDown() throws Exception {
- try {
- DeviceConfig.setProperties(mOriginalBiometricsFlags);
- } catch (DeviceConfig.BadConfigException e) {
- Log.e(TAG, "Failed to reset biometrics flags to the original values before test. "
- + e);
- }
+ public void tearDown() {
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_BIOMETRICS,
+ BinaryTransparencyService.KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION,
+ mOriginalBiometricsFlag, false /* makeDefault */);
LocalServices.removeServiceForTest(PackageManagerInternal.class);
}
diff --git a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
index 92c6db5b7b96..5240f581fd9f 100644
--- a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
@@ -166,8 +166,7 @@ public class GestureLauncherServiceTest {
new GestureLauncherService(
mContext, mMetricsLogger, mQuickAccessWalletClient, mUiEventLogger);
- withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
- withDefaultDoubleTapPowerGestureAction(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
+ Settings.Secure.clearProviderForTest();
}
private WalletLaunchedReceiver registerWalletLaunchedReceiver(String action) {
@@ -223,7 +222,7 @@ public class GestureLauncherServiceTest {
withDoubleTapPowerModeConfigValue(
DOUBLE_TAP_POWER_DISABLED_MODE);
withMultiTargetDoubleTapPowerGestureEnableSettingValue(false);
- withDefaultDoubleTapPowerGestureAction(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
+ withDoubleTapPowerGestureActionSettingValue(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
mContext, FAKE_USER_ID));
@@ -244,7 +243,7 @@ public class GestureLauncherServiceTest {
public void testIsCameraDoubleTapPowerSettingEnabled_flagEnabled_configFalseSettingEnabled() {
withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_DISABLED_MODE);
withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
- withDefaultDoubleTapPowerGestureAction(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
+ withDoubleTapPowerGestureActionSettingValue(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
mContext, FAKE_USER_ID));
@@ -265,7 +264,7 @@ public class GestureLauncherServiceTest {
public void testIsCameraDoubleTapPowerSettingEnabled_flagEnabled_configTrueSettingDisabled() {
withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
withMultiTargetDoubleTapPowerGestureEnableSettingValue(false);
- withDefaultDoubleTapPowerGestureAction(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
+ withDoubleTapPowerGestureActionSettingValue(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
mContext, FAKE_USER_ID));
@@ -286,7 +285,7 @@ public class GestureLauncherServiceTest {
public void testIsCameraDoubleTapPowerSettingEnabled_flagEnabled_configTrueSettingEnabled() {
withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
- withDefaultDoubleTapPowerGestureAction(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
+ withDoubleTapPowerGestureActionSettingValue(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
assertTrue(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
mContext, FAKE_USER_ID));
@@ -329,7 +328,31 @@ public class GestureLauncherServiceTest {
public void testIsCameraDoubleTapPowerSettingEnabled_actionWallet() {
withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
- withDefaultDoubleTapPowerGestureAction(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER);
+ withDoubleTapPowerGestureActionSettingValue(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER);
+
+ assertFalse(
+ mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
+ mContext, FAKE_USER_ID));
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
+ public void testIsCameraDoubleTapPowerSettingEnabled_defaultActionCamera() {
+ withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
+ withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
+ withDefaultDoubleTapPowerGestureActionConfig(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
+
+ assertTrue(
+ mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
+ mContext, FAKE_USER_ID));
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
+ public void testIsCameraDoubleTapPowerSettingEnabled_defaultActionNotCamera() {
+ withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
+ withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
+ withDefaultDoubleTapPowerGestureActionConfig(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER);
assertFalse(
mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
@@ -341,7 +364,7 @@ public class GestureLauncherServiceTest {
public void testIsWalletDoubleTapPowerSettingEnabled() {
withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
- withDefaultDoubleTapPowerGestureAction(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER);
+ withDoubleTapPowerGestureActionSettingValue(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER);
assertTrue(
mGestureLauncherService.isWalletDoubleTapPowerSettingEnabled(
@@ -353,7 +376,7 @@ public class GestureLauncherServiceTest {
public void testIsWalletDoubleTapPowerSettingEnabled_configDisabled() {
withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_DISABLED_MODE);
withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
- withDefaultDoubleTapPowerGestureAction(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER);
+ withDoubleTapPowerGestureActionSettingValue(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER);
assertFalse(
mGestureLauncherService.isWalletDoubleTapPowerSettingEnabled(
@@ -365,7 +388,7 @@ public class GestureLauncherServiceTest {
public void testIsWalletDoubleTapPowerSettingEnabled_settingDisabled() {
withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
withMultiTargetDoubleTapPowerGestureEnableSettingValue(false);
- withDefaultDoubleTapPowerGestureAction(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER);
+ withDoubleTapPowerGestureActionSettingValue(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER);
assertFalse(
mGestureLauncherService.isWalletDoubleTapPowerSettingEnabled(
@@ -377,7 +400,31 @@ public class GestureLauncherServiceTest {
public void testIsWalletDoubleTapPowerSettingEnabled_actionCamera() {
withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
- withDefaultDoubleTapPowerGestureAction(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
+ withDoubleTapPowerGestureActionSettingValue(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
+
+ assertFalse(
+ mGestureLauncherService.isWalletDoubleTapPowerSettingEnabled(
+ mContext, FAKE_USER_ID));
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
+ public void testIsWalletDoubleTapPowerSettingEnabled_defaultActionWallet() {
+ withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
+ withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
+ withDefaultDoubleTapPowerGestureActionConfig(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER);
+
+ assertTrue(
+ mGestureLauncherService.isWalletDoubleTapPowerSettingEnabled(
+ mContext, FAKE_USER_ID));
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
+ public void testIsWalletDoubleTapPowerSettingEnabled_defaultActionNotWallet() {
+ withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
+ withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
+ withDefaultDoubleTapPowerGestureActionConfig(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
assertFalse(
mGestureLauncherService.isWalletDoubleTapPowerSettingEnabled(
@@ -1858,7 +1905,7 @@ public class GestureLauncherServiceTest {
UserHandle.USER_CURRENT);
}
- private void withDefaultDoubleTapPowerGestureAction(int action) {
+ private void withDoubleTapPowerGestureActionSettingValue(int action) {
Settings.Secure.putIntForUser(
mContentResolver,
Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE,
@@ -1866,6 +1913,12 @@ public class GestureLauncherServiceTest {
UserHandle.USER_CURRENT);
}
+ private void withDefaultDoubleTapPowerGestureActionConfig(int action) {
+ when(mResources.getInteger(
+ com.android.internal.R.integer.config_doubleTapPowerGestureMultiTargetDefaultAction
+ )).thenReturn(action);
+ }
+
private void withEmergencyGestureEnabledConfigValue(boolean enableConfigValue) {
when(mResources.getBoolean(
com.android.internal.R.bool.config_emergencyGestureEnabled))
@@ -1931,7 +1984,7 @@ public class GestureLauncherServiceTest {
}
private void enableWalletGesture() {
- withDefaultDoubleTapPowerGestureAction(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER);
+ withDoubleTapPowerGestureActionSettingValue(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER);
withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
@@ -1951,7 +2004,7 @@ public class GestureLauncherServiceTest {
withDoubleTapPowerModeConfigValue(
DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
- withDefaultDoubleTapPowerGestureAction(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
+ withDoubleTapPowerGestureActionSettingValue(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
} else {
withCameraDoubleTapPowerEnableConfigValue(true);
withCameraDoubleTapPowerDisableSettingValue(0);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java
index 464fee2bfc11..fb31cfe762f2 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java
@@ -20,6 +20,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
import static android.view.WindowManagerPolicyConstants.FLAG_PASS_TO_USER;
+import static com.android.hardware.input.Flags.FLAG_ENABLE_TALKBACK_AND_MAGNIFIER_KEY_GESTURES;
import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_AUTOCLICK;
import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER;
import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS;
@@ -39,6 +40,10 @@ import android.content.Context;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Looper;
import android.os.SystemClock;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
import android.util.SparseArray;
import android.view.Display;
@@ -55,12 +60,14 @@ import com.android.server.LocalServices;
import com.android.server.accessibility.gestures.TouchExplorer;
import com.android.server.accessibility.magnification.FullScreenMagnificationGestureHandler;
import com.android.server.accessibility.magnification.MagnificationGestureHandler;
+import com.android.server.accessibility.magnification.MagnificationKeyHandler;
import com.android.server.accessibility.magnification.MagnificationProcessor;
import com.android.server.accessibility.magnification.WindowMagnificationGestureHandler;
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.Mock;
@@ -88,8 +95,16 @@ public class AccessibilityInputFilterTest {
| FLAG_FEATURE_INJECT_MOTION_EVENTS
| FLAG_FEATURE_FILTER_KEY_EVENTS;
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
// The expected order of EventStreamTransformations.
private final Class[] mExpectedEventHandlerTypes =
+ {MagnificationKeyHandler.class, KeyboardInterceptor.class, MotionEventInjector.class,
+ FullScreenMagnificationGestureHandler.class, TouchExplorer.class,
+ AutoclickController.class, AccessibilityInputFilter.class};
+
+ private final Class[] mExpectedEventHandlerTypesWithoutMagKeyboard =
{KeyboardInterceptor.class, MotionEventInjector.class,
FullScreenMagnificationGestureHandler.class, TouchExplorer.class,
AutoclickController.class, AccessibilityInputFilter.class};
@@ -176,6 +191,7 @@ public class AccessibilityInputFilterTest {
}
@Test
+ @RequiresFlagsEnabled(FLAG_ENABLE_TALKBACK_AND_MAGNIFIER_KEY_GESTURES)
public void testEventHandler_shouldIncreaseAndHaveCorrectOrderAfterOnDisplayAdded() {
prepareLooper();
@@ -191,9 +207,9 @@ public class AccessibilityInputFilterTest {
EventStreamTransformation next = mEventHandler.get(SECOND_DISPLAY);
assertNotNull(next);
- // Start from index 1 because KeyboardInterceptor only exists in EventHandler for
- // DEFAULT_DISPLAY.
- for (int i = 1; next != null; i++) {
+ // Start from index 2 because KeyboardInterceptor and MagnificationKeyHandler only exist in
+ // EventHandler for DEFAULT_DISPLAY.
+ for (int i = 2; next != null; i++) {
assertEquals(next.getClass(), mExpectedEventHandlerTypes[i]);
next = next.getNext();
}
@@ -232,6 +248,7 @@ public class AccessibilityInputFilterTest {
}
@Test
+ @RequiresFlagsEnabled(FLAG_ENABLE_TALKBACK_AND_MAGNIFIER_KEY_GESTURES)
public void testEventHandler_shouldHaveCorrectOrderForEventStreamTransformation() {
prepareLooper();
@@ -248,10 +265,36 @@ public class AccessibilityInputFilterTest {
}
next = mEventHandler.get(SECOND_DISPLAY);
+ // Start from index 2 because KeyboardInterceptor and MagnificationKeyHandler only exist
+ // in EventHandler for DEFAULT_DISPLAY.
+ for (int i = 2; next != null; i++) {
+ assertEquals(next.getClass(), mExpectedEventHandlerTypes[i]);
+ next = next.getNext();
+ }
+ }
+
+ @Test
+ @RequiresFlagsDisabled(FLAG_ENABLE_TALKBACK_AND_MAGNIFIER_KEY_GESTURES)
+ public void testEventHandler_shouldHaveCorrectOrderForEventStreamTransformation_noMagKeys() {
+ prepareLooper();
+
+ setDisplayCount(2);
+ mA11yInputFilter.setUserAndEnabledFeatures(0, mFeatures);
+ assertEquals(2, mEventHandler.size());
+
+ // Check if mEventHandler for each display has correct order of the
+ // EventStreamTransformations.
+ EventStreamTransformation next = mEventHandler.get(DEFAULT_DISPLAY);
+ for (int i = 0; next != null; i++) {
+ assertEquals(next.getClass(), mExpectedEventHandlerTypesWithoutMagKeyboard[i]);
+ next = next.getNext();
+ }
+
+ next = mEventHandler.get(SECOND_DISPLAY);
// Start from index 1 because KeyboardInterceptor only exists in EventHandler for
// DEFAULT_DISPLAY.
for (int i = 1; next != null; i++) {
- assertEquals(next.getClass(), mExpectedEventHandlerTypes[i]);
+ assertEquals(next.getClass(), mExpectedEventHandlerTypesWithoutMagKeyboard[i]);
next = next.getNext();
}
}
@@ -387,7 +430,6 @@ public class AccessibilityInputFilterTest {
assertNotNull(handler);
assertEquals(WindowMagnificationGestureHandler.class, handler.getClass());
assertEquals(nextEventStream.getClass(), handler.getNext().getClass());
-
}
@Test public void
@@ -412,6 +454,32 @@ public class AccessibilityInputFilterTest {
assertEquals(nextEventStream.getClass(), handler.getNext().getClass());
}
+ @Test
+ @RequiresFlagsEnabled(FLAG_ENABLE_TALKBACK_AND_MAGNIFIER_KEY_GESTURES)
+ public void testEnabledFeatures_windowMagnificationMode_expectedMagnificationKeyHandler() {
+ prepareLooper();
+ doReturn(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW).when(
+ mAms).getMagnificationMode(DEFAULT_DISPLAY);
+
+ mA11yInputFilter.setUserAndEnabledFeatures(0, mFeatures);
+
+ MagnificationKeyHandler handler = getMagnificationKeyHandlerFromEventHandler();
+ assertNotNull(handler);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_ENABLE_TALKBACK_AND_MAGNIFIER_KEY_GESTURES)
+ public void testEnabledFeatures_fullscreenMagnificationMode_expectedMagnificationKeyHandler() {
+ prepareLooper();
+ doReturn(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN).when(
+ mAms).getMagnificationMode(DEFAULT_DISPLAY);
+
+ mA11yInputFilter.setUserAndEnabledFeatures(0, mFeatures);
+
+ MagnificationKeyHandler handler = getMagnificationKeyHandlerFromEventHandler();
+ assertNotNull(handler);
+ }
+
private static void prepareLooper() {
if (Looper.myLooper() == null) {
Looper.prepare();
@@ -458,4 +526,16 @@ public class AccessibilityInputFilterTest {
}
return null;
}
+
+ @Nullable
+ private MagnificationKeyHandler getMagnificationKeyHandlerFromEventHandler() {
+ EventStreamTransformation next = mEventHandler.get(DEFAULT_DISPLAY);
+ while (next != null) {
+ if (next instanceof MagnificationKeyHandler) {
+ return (MagnificationKeyHandler) next;
+ }
+ next = next.getNext();
+ }
+ return null;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index dafe4827b2fe..5602fb76e6f5 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -829,26 +829,6 @@ public class AccessibilityManagerServiceTest {
@SmallTest
@Test
- @DisableFlags(com.android.systemui.Flags.FLAG_HEARING_AIDS_QS_TILE_DIALOG)
- public void testPerformAccessibilityShortcut_hearingAids_startActivityWithExpectedComponent() {
- final AccessibilityUserState userState = mA11yms.mUserStates.get(
- mA11yms.getCurrentUserIdLocked());
- mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
- userState.updateShortcutTargetsLocked(
- Set.of(ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString()), HARDWARE);
-
- mA11yms.performAccessibilityShortcut(
- Display.DEFAULT_DISPLAY, HARDWARE,
- ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString());
- mTestableLooper.processAllMessages();
-
- assertStartActivityWithExpectedComponentName(mTestableContext.getMockContext(),
- ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString());
- }
-
- @SmallTest
- @Test
- @EnableFlags(com.android.systemui.Flags.FLAG_HEARING_AIDS_QS_TILE_DIALOG)
public void testPerformAccessibilityShortcut_hearingAids_sendExpectedBroadcast() {
final AccessibilityUserState userState = mA11yms.mUserStates.get(
mA11yms.getCurrentUserIdLocked());
@@ -1510,7 +1490,6 @@ public class AccessibilityManagerServiceTest {
}
@Test
- @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void notifyQuickSettingsTilesChanged_statusBarServiceNotGranted_throwsException() {
mFakePermissionEnforcer.revoke(Manifest.permission.STATUS_BAR_SERVICE);
mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
@@ -1523,7 +1502,6 @@ public class AccessibilityManagerServiceTest {
}
@Test
- @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void notifyQuickSettingsTilesChanged_manageAccessibilityNotGranted_throwsException() {
mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
mTestableContext.getTestablePermissions().setPermission(
@@ -1537,7 +1515,6 @@ public class AccessibilityManagerServiceTest {
}
@Test
- @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void notifyQuickSettingsTilesChanged_qsTileChanges_updateA11yTilesInQsPanel() {
mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
@@ -1557,7 +1534,6 @@ public class AccessibilityManagerServiceTest {
}
@Test
- @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void notifyQuickSettingsTilesChanged_sameQsTiles_noUpdateToA11yTilesInQsPanel() {
notifyQuickSettingsTilesChanged_qsTileChanges_updateA11yTilesInQsPanel();
List<ComponentName> tiles =
@@ -1574,7 +1550,6 @@ public class AccessibilityManagerServiceTest {
}
@Test
- @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void notifyQuickSettingsTilesChanged_serviceWarningRequired_qsShortcutRemainDisabled() {
mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
@@ -1593,7 +1568,6 @@ public class AccessibilityManagerServiceTest {
}
@Test
- @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void notifyQuickSettingsTilesChanged_serviceWarningNotRequired_qsShortcutEnabled() {
mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
@@ -1615,7 +1589,6 @@ public class AccessibilityManagerServiceTest {
}
@Test
- @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void notifyQuickSettingsTilesChanged_addFrameworkTile_qsShortcutEnabled() {
mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
@@ -1638,7 +1611,6 @@ public class AccessibilityManagerServiceTest {
}
@Test
- @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void notifyQuickSettingsTilesChanged_removeFrameworkTile_qsShortcutDisabled() {
notifyQuickSettingsTilesChanged_addFrameworkTile_qsShortcutEnabled();
Set<ComponentName> qsTiles = mA11yms.getCurrentUserState().getA11yQsTilesInQsPanel();
@@ -1656,7 +1628,6 @@ public class AccessibilityManagerServiceTest {
}
@Test
- @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
@DisableFlags(android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SECURE_SETTINGS_ON_HSUM_DEVICE)
public void restoreShortcutTargetsAssumeUser0_qs_a11yQsTargetsRestored() {
assumeTrue("The test is setup to run as a user 0",
@@ -1665,8 +1636,7 @@ public class AccessibilityManagerServiceTest {
}
@Test
- @EnableFlags({android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT,
- android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SECURE_SETTINGS_ON_HSUM_DEVICE})
+ @EnableFlags(android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SECURE_SETTINGS_ON_HSUM_DEVICE)
public void restoreShortcutTargets_qs_a11yQsTargetsRestored() {
String daltonizerTile =
AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME.flattenToString();
@@ -1689,40 +1659,6 @@ public class AccessibilityManagerServiceTest {
}
@Test
- @DisableFlags({android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT,
- android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SECURE_SETTINGS_ON_HSUM_DEVICE})
- public void restoreShortcutTargetsAssumeUser0_qs_a11yQsTargetsNotRestored() {
- assumeTrue("The test is setup to run as a user 0",
- mTestableContext.getUserId() == UserHandle.USER_SYSTEM);
- restoreShortcutTargets_qs_a11yQsTargetsNotRestored();
- }
-
- @Test
- @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
- @EnableFlags(android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SECURE_SETTINGS_ON_HSUM_DEVICE)
- public void restoreShortcutTargets_qs_a11yQsTargetsNotRestored() {
- String daltonizerTile =
- AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME.flattenToString();
- String colorInversionTile =
- AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME.flattenToString();
- final AccessibilityUserState userState = new AccessibilityUserState(
- mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
- userState.updateShortcutTargetsLocked(Set.of(daltonizerTile), QUICK_SETTINGS);
- putShortcutSettingForUser(QUICK_SETTINGS, daltonizerTile, userState.mUserId);
- mA11yms.mUserStates.put(userState.mUserId, userState);
-
- broadcastSettingRestored(
- ShortcutUtils.convertToKey(QUICK_SETTINGS),
- /*newValue=*/colorInversionTile, userState.mUserId);
-
- Set<String> expected = Set.of(daltonizerTile);
- assertThat(readStringsFromSetting(ShortcutUtils.convertToKey(QUICK_SETTINGS)))
- .containsExactlyElementsIn(expected);
- assertThat(userState.getShortcutTargetsLocked(QUICK_SETTINGS))
- .containsExactlyElementsIn(expected);
- }
-
- @Test
public void onHandleForceStop_dontDoIt_packageEnabled_returnsTrue() {
setupShortcutTargetServices();
AccessibilityUserState userState = mA11yms.getCurrentUserState();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java
index f371823473ef..1a974458403f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java
@@ -425,7 +425,6 @@ public class ProxyManagerTest {
@Test
public void testRegisterProxy_registersVirtualDeviceListener() throws RemoteException {
- mSetFlagsRule.enableFlags(android.companion.virtual.flags.Flags.FLAG_VDM_PUBLIC_APIS);
registerProxy(DISPLAY_ID);
verify(mMockIVirtualDeviceManager, times(1)).registerVirtualDeviceListener(any());
@@ -434,7 +433,6 @@ public class ProxyManagerTest {
@Test
public void testRegisterMultipleProxies_registersOneVirtualDeviceListener()
throws RemoteException {
- mSetFlagsRule.enableFlags(android.companion.virtual.flags.Flags.FLAG_VDM_PUBLIC_APIS);
registerProxy(DISPLAY_ID);
registerProxy(DISPLAY_2_ID);
@@ -443,7 +441,6 @@ public class ProxyManagerTest {
@Test
public void testUnregisterProxy_unregistersVirtualDeviceListener() throws RemoteException {
- mSetFlagsRule.enableFlags(android.companion.virtual.flags.Flags.FLAG_VDM_PUBLIC_APIS);
registerProxy(DISPLAY_ID);
mProxyManager.unregisterProxy(DISPLAY_ID);
@@ -454,7 +451,6 @@ public class ProxyManagerTest {
@Test
public void testUnregisterProxy_onlyUnregistersVirtualDeviceListenerOnLastProxyRemoval()
throws RemoteException {
- mSetFlagsRule.enableFlags(android.companion.virtual.flags.Flags.FLAG_VDM_PUBLIC_APIS);
registerProxy(DISPLAY_ID);
registerProxy(DISPLAY_2_ID);
@@ -468,7 +464,6 @@ public class ProxyManagerTest {
@Test
public void testRegisteredProxy_virtualDeviceClosed_proxyClosed()
throws RemoteException {
- mSetFlagsRule.enableFlags(android.companion.virtual.flags.Flags.FLAG_VDM_PUBLIC_APIS);
registerProxy(DISPLAY_ID);
assertThat(mProxyManager.isProxyedDeviceId(DEVICE_ID)).isTrue();
@@ -490,7 +485,6 @@ public class ProxyManagerTest {
@Test
public void testRegisteredProxy_unrelatedVirtualDeviceClosed_proxyNotClosed()
throws RemoteException {
- mSetFlagsRule.enableFlags(android.companion.virtual.flags.Flags.FLAG_VDM_PUBLIC_APIS);
registerProxy(DISPLAY_ID);
assertThat(mProxyManager.isProxyedDeviceId(DEVICE_ID)).isTrue();
@@ -507,17 +501,6 @@ public class ProxyManagerTest {
assertThat(mProxyManager.isProxyedDisplay(DISPLAY_ID)).isTrue();
}
- @Test
- public void testRegisterProxy_doesNotRegisterVirtualDeviceListener_flagDisabled()
- throws RemoteException {
- mSetFlagsRule.disableFlags(android.companion.virtual.flags.Flags.FLAG_VDM_PUBLIC_APIS);
- registerProxy(DISPLAY_ID);
- mProxyManager.unregisterProxy(DISPLAY_ID);
-
- verify(mMockIVirtualDeviceManager, never()).registerVirtualDeviceListener(any());
- verify(mMockIVirtualDeviceManager, never()).unregisterVirtualDeviceListener(any());
- }
-
private void registerProxy(int displayId) {
try {
mProxyManager.registerProxy(mMockAccessibilityServiceClient, displayId, anyInt(),
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationKeyHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationKeyHandlerTest.java
new file mode 100644
index 000000000000..d1ef33d8fb70
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationKeyHandlerTest.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.accessibility.magnification;
+
+import static com.android.hardware.input.Flags.FLAG_ENABLE_TALKBACK_AND_MAGNIFIER_KEY_GESTURES;
+import static com.android.server.accessibility.magnification.MagnificationController.PAN_DIRECTION_DOWN;
+import static com.android.server.accessibility.magnification.MagnificationController.PAN_DIRECTION_LEFT;
+import static com.android.server.accessibility.magnification.MagnificationController.PAN_DIRECTION_RIGHT;
+import static com.android.server.accessibility.magnification.MagnificationController.PAN_DIRECTION_UP;
+import static com.android.server.accessibility.magnification.MagnificationController.ZOOM_DIRECTION_IN;
+import static com.android.server.accessibility.magnification.MagnificationController.ZOOM_DIRECTION_OUT;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.view.Display;
+import android.view.KeyEvent;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.accessibility.EventStreamTransformation;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link MagnificationKeyHandler}.
+ */
+@RunWith(AndroidJUnit4.class)
+@RequiresFlagsEnabled(FLAG_ENABLE_TALKBACK_AND_MAGNIFIER_KEY_GESTURES)
+public class MagnificationKeyHandlerTest {
+
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
+ private MagnificationKeyHandler mMkh;
+
+ @Mock
+ MagnificationKeyHandler.Callback mCallback;
+
+ @Mock
+ EventStreamTransformation mNextHandler;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mMkh = new MagnificationKeyHandler(mCallback);
+ mMkh.setNext(mNextHandler);
+ }
+
+ @Test
+ public void onKeyEvent_unusedKeyPress_sendToNext() {
+ final KeyEvent event = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_L, 0, 0);
+ mMkh.onKeyEvent(event, 0);
+
+ // No callbacks were called.
+ verify(mCallback, times(0)).onPanMagnificationStart(anyInt(), anyInt());
+ verify(mCallback, times(0)).onPanMagnificationStop(anyInt(), anyInt());
+ verify(mCallback, times(0)).onScaleMagnificationStart(anyInt(), anyInt());
+ verify(mCallback, times(0)).onScaleMagnificationStop(anyInt(), anyInt());
+
+ // The event was passed on.
+ verify(mNextHandler, times(1)).onKeyEvent(event, 0);
+ }
+
+ @Test
+ public void onKeyEvent_arrowKeyPressWithIncorrectModifiers_sendToNext() {
+ final KeyEvent event =
+ new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT,
+ 0, KeyEvent.META_ALT_ON);
+ mMkh.onKeyEvent(event, 0);
+
+ // No callbacks were called.
+ verify(mCallback, times(0)).onPanMagnificationStart(anyInt(), anyInt());
+ verify(mCallback, times(0)).onPanMagnificationStop(anyInt(), anyInt());
+ verify(mCallback, times(0)).onScaleMagnificationStart(anyInt(), anyInt());
+ verify(mCallback, times(0)).onScaleMagnificationStop(anyInt(), anyInt());
+
+ // The event was passed on.
+ verify(mNextHandler, times(1)).onKeyEvent(event, 0);
+ }
+
+ @Test
+ public void onKeyEvent_unusedKeyPressWithCorrectModifiers_sendToNext() {
+ final KeyEvent event =
+ new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_J, 0,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON);
+ mMkh.onKeyEvent(event, 0);
+
+ // No callbacks were called.
+ verify(mCallback, times(0)).onPanMagnificationStart(anyInt(), anyInt());
+ verify(mCallback, times(0)).onPanMagnificationStop(anyInt(), anyInt());
+ verify(mCallback, times(0)).onScaleMagnificationStart(anyInt(), anyInt());
+ verify(mCallback, times(0)).onScaleMagnificationStop(anyInt(), anyInt());
+
+ // The event was passed on.
+ verify(mNextHandler, times(1)).onKeyEvent(event, 0);
+ }
+
+ @Test
+ public void onKeyEvent_panStartAndEnd_left() {
+ testPanMagnification(KeyEvent.KEYCODE_DPAD_LEFT, PAN_DIRECTION_LEFT);
+ }
+
+ @Test
+ public void onKeyEvent_panStartAndEnd_right() {
+ testPanMagnification(KeyEvent.KEYCODE_DPAD_RIGHT, PAN_DIRECTION_RIGHT);
+ }
+
+ @Test
+ public void onKeyEvent_panStartAndEnd_up() {
+ testPanMagnification(KeyEvent.KEYCODE_DPAD_UP, PAN_DIRECTION_UP);
+ }
+
+ @Test
+ public void onKeyEvent_panStartAndEnd_down() {
+ testPanMagnification(KeyEvent.KEYCODE_DPAD_DOWN, PAN_DIRECTION_DOWN);
+ }
+
+ @Test
+ public void onKeyEvent_scaleStartAndEnd_zoomIn() {
+ testScaleMagnification(KeyEvent.KEYCODE_EQUALS, ZOOM_DIRECTION_IN);
+ }
+
+ @Test
+ public void onKeyEvent_scaleStartAndEnd_zoomOut() {
+ testScaleMagnification(KeyEvent.KEYCODE_MINUS, ZOOM_DIRECTION_OUT);
+ }
+
+ @Test
+ public void onKeyEvent_panStartAndStop_diagonal() {
+ final KeyEvent downLeftEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_DPAD_LEFT, 0, KeyEvent.META_META_ON | KeyEvent.META_ALT_ON);
+ mMkh.onKeyEvent(downLeftEvent, 0);
+ verify(mCallback, times(1)).onPanMagnificationStart(Display.DEFAULT_DISPLAY,
+ PAN_DIRECTION_LEFT);
+ verify(mCallback, times(0)).onPanMagnificationStop(anyInt(), anyInt());
+
+ // Also press the down arrow key.
+ final KeyEvent downDownEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_DPAD_DOWN, 0, KeyEvent.META_META_ON | KeyEvent.META_ALT_ON);
+ mMkh.onKeyEvent(downDownEvent, 0);
+ verify(mCallback, times(1)).onPanMagnificationStart(Display.DEFAULT_DISPLAY,
+ PAN_DIRECTION_LEFT);
+ verify(mCallback, times(1)).onPanMagnificationStart(Display.DEFAULT_DISPLAY,
+ PAN_DIRECTION_DOWN);
+ verify(mCallback, times(0)).onPanMagnificationStop(anyInt(), anyInt());
+
+ // Lift the left arrow key.
+ final KeyEvent upLeftEvent = new KeyEvent(0, 0, KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_DPAD_LEFT, 0, KeyEvent.META_META_ON | KeyEvent.META_ALT_ON);
+ mMkh.onKeyEvent(upLeftEvent, 0);
+ verify(mCallback, times(1)).onPanMagnificationStart(Display.DEFAULT_DISPLAY,
+ PAN_DIRECTION_LEFT);
+ verify(mCallback, times(1)).onPanMagnificationStart(Display.DEFAULT_DISPLAY,
+ PAN_DIRECTION_DOWN);
+ verify(mCallback, times(1)).onPanMagnificationStop(Display.DEFAULT_DISPLAY,
+ PAN_DIRECTION_LEFT);
+ verify(mCallback, times(0)).onPanMagnificationStop(Display.DEFAULT_DISPLAY,
+ PAN_DIRECTION_DOWN);
+
+ // Lift the down arrow key.
+ final KeyEvent upDownEvent = new KeyEvent(0, 0, KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_DPAD_DOWN, 0, KeyEvent.META_META_ON | KeyEvent.META_ALT_ON);
+ mMkh.onKeyEvent(upDownEvent, 0);
+ verify(mCallback, times(1)).onPanMagnificationStart(Display.DEFAULT_DISPLAY,
+ PAN_DIRECTION_LEFT);
+ verify(mCallback, times(1)).onPanMagnificationStart(Display.DEFAULT_DISPLAY,
+ PAN_DIRECTION_DOWN);
+ verify(mCallback, times(1)).onPanMagnificationStop(Display.DEFAULT_DISPLAY,
+ PAN_DIRECTION_LEFT);
+ verify(mCallback, times(1)).onPanMagnificationStop(Display.DEFAULT_DISPLAY,
+ PAN_DIRECTION_DOWN);
+
+ // The event was not passed on.
+ verify(mNextHandler, times(0)).onKeyEvent(any(), anyInt());
+ }
+
+ private void testPanMagnification(int keyCode, int panDirection) {
+ final KeyEvent downEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, keyCode, 0,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON);
+ mMkh.onKeyEvent(downEvent, 0);
+
+ // Pan started.
+ verify(mCallback, times(1)).onPanMagnificationStart(Display.DEFAULT_DISPLAY, panDirection);
+ verify(mCallback, times(0)).onPanMagnificationStop(anyInt(), anyInt());
+
+ final KeyEvent upEvent = new KeyEvent(0, 0, KeyEvent.ACTION_UP, keyCode, 0,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON);
+ mMkh.onKeyEvent(upEvent, 0);
+
+ // Pan ended.
+ verify(mCallback, times(1)).onPanMagnificationStart(Display.DEFAULT_DISPLAY, panDirection);
+ verify(mCallback, times(1)).onPanMagnificationStop(Display.DEFAULT_DISPLAY, panDirection);
+
+ // Scale callbacks were not called.
+ verify(mCallback, times(0)).onScaleMagnificationStart(anyInt(), anyInt());
+ verify(mCallback, times(0)).onScaleMagnificationStop(anyInt(), anyInt());
+
+ // The events were not passed on.
+ verify(mNextHandler, times(0)).onKeyEvent(any(), anyInt());
+ }
+
+ private void testScaleMagnification(int keyCode, int zoomDirection) {
+ final KeyEvent downEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, keyCode, 0,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON);
+ mMkh.onKeyEvent(downEvent, 0);
+
+ // Scale started.
+ verify(mCallback, times(1)).onScaleMagnificationStart(Display.DEFAULT_DISPLAY,
+ zoomDirection);
+ verify(mCallback, times(0)).onScaleMagnificationStop(anyInt(), anyInt());
+
+ final KeyEvent upEvent = new KeyEvent(0, 0, KeyEvent.ACTION_UP, keyCode, 0,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON);
+ mMkh.onKeyEvent(upEvent, 0);
+
+ // Scale ended.
+ verify(mCallback, times(1)).onScaleMagnificationStart(Display.DEFAULT_DISPLAY,
+ zoomDirection);
+ verify(mCallback, times(1)).onScaleMagnificationStop(Display.DEFAULT_DISPLAY,
+ zoomDirection);
+
+ // Pan callbacks were not called.
+ verify(mCallback, times(0)).onPanMagnificationStart(anyInt(), anyInt());
+ verify(mCallback, times(0)).onPanMagnificationStop(anyInt(), anyInt());
+
+ // The events were not passed on.
+ verify(mNextHandler, times(0)).onKeyEvent(any(), anyInt());
+
+ }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
index 4d1d17f184d1..77c2447fc55f 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
@@ -31,7 +31,6 @@ import static org.mockito.Mockito.when;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.VirtualDevice;
-import android.companion.virtual.flags.Flags;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -109,8 +108,6 @@ public class VirtualDeviceTest {
@Test
public void virtualDevice_getDisplayIds() throws Exception {
- mSetFlagsRule.enableFlags(Flags.FLAG_VDM_PUBLIC_APIS);
-
VirtualDevice virtualDevice =
new VirtualDevice(
mVirtualDevice, VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null);
@@ -125,8 +122,6 @@ public class VirtualDeviceTest {
@Test
public void virtualDevice_hasCustomSensorSupport() throws Exception {
- mSetFlagsRule.enableFlags(Flags.FLAG_VDM_PUBLIC_APIS);
-
VirtualDevice virtualDevice =
new VirtualDevice(
mVirtualDevice, VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null);
@@ -140,7 +135,6 @@ public class VirtualDeviceTest {
@Test
public void virtualDevice_hasCustomAudioInputSupport() throws Exception {
- mSetFlagsRule.enableFlags(Flags.FLAG_VDM_PUBLIC_APIS);
mSetFlagsRule.enableFlags(android.media.audiopolicy.Flags.FLAG_AUDIO_MIX_TEST_API);
VirtualDevice virtualDevice =
@@ -160,8 +154,6 @@ public class VirtualDeviceTest {
@Test
public void virtualDevice_hasCustomCameraSupport() throws Exception {
- mSetFlagsRule.enableFlags(Flags.FLAG_VDM_PUBLIC_APIS);
-
VirtualDevice virtualDevice =
new VirtualDevice(
mVirtualDevice, VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 861e72d4ac79..cfdf17668229 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -2868,6 +2868,9 @@ public class HdmiCecLocalDevicePlaybackTest {
assertThat(mPowerManager.isInteractive()).isTrue();
mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+
mTestLooper.moveTimeForward(MONITORING_INTERVAL_MS);
mTestLooper.dispatchAll();
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 776f05dfb6ea..f536cae53e3a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -167,7 +167,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
* Test for {@link ShortcutService#getLastResetTimeLocked()} and
* {@link ShortcutService#getNextResetTimeLocked()}.
*/
- public void testUpdateAndGetNextResetTimeLocked() {
+ public void disabled_testUpdateAndGetNextResetTimeLocked() {
assertResetTimes(START_TIME, START_TIME + INTERVAL);
// Advance clock.
@@ -284,7 +284,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
assertEquals(START_TIME + 5 * INTERVAL, mManager.getRateLimitResetTime());
}
- public void testSetDynamicShortcuts() {
+ public void disabled_testSetDynamicShortcuts() {
setCaller(CALLING_PACKAGE_1, USER_10);
final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.icon1);
@@ -596,7 +596,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
eq(CALLING_PACKAGE_2), any(), eq(USER_10));
}
- public void testUnlimitedCalls() {
+ public void disabled_testUnlimitedCalls() {
setCaller(CALLING_PACKAGE_1, USER_10);
final ShortcutInfo si1 = makeShortcut("shortcut1");
@@ -1205,7 +1205,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
maxSize));
}
- public void testShrinkBitmap() {
+ public void disabled_testShrinkBitmap() {
checkShrinkBitmap(32, 32, R.drawable.black_512x512, 32);
checkShrinkBitmap(511, 511, R.drawable.black_512x512, 511);
checkShrinkBitmap(512, 512, R.drawable.black_512x512, 512);
@@ -1302,7 +1302,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
assertFalse(p11_1_3.getName().contains("_"));
}
- public void testUpdateShortcuts() {
+ public void disabled_testUpdateShortcuts() {
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
assertTrue(mManager.setDynamicShortcuts(list(
makeShortcut("s1"),
@@ -1433,7 +1433,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
});
}
- public void testUpdateShortcuts_icons() {
+ public void disabled_testUpdateShortcuts_icons() {
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
assertTrue(mManager.setDynamicShortcuts(list(
makeShortcut("s1")
@@ -1527,7 +1527,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
});
}
- public void testShortcutManagerGetShortcuts_shortcutTypes() {
+ public void disabled_testShortcutManagerGetShortcuts_shortcutTypes() {
// Create 3 manifest and 3 dynamic shortcuts
addManifestShortcutResource(
@@ -2281,7 +2281,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
assertEquals("ABC", findById(list, "s1").getTitle());
}
- public void testPinShortcutAndGetPinnedShortcuts() {
+ public void disabled_testPinShortcutAndGetPinnedShortcuts() {
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
final ShortcutInfo s1_1 = makeShortcutWithTimestamp("s1", 1000);
final ShortcutInfo s1_2 = makeShortcutWithTimestamp("s2", 2000);
@@ -3478,7 +3478,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
});
}
- public void testStartShortcut() {
+ public void disabled_testStartShortcut() {
// Create some shortcuts.
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
final ShortcutInfo s1_1 = makeShortcut(
@@ -3902,7 +3902,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
// === Test for persisting ===
- public void testSaveAndLoadUser_empty() {
+ public void disabled_testSaveAndLoadUser_empty() {
assertTrue(mManager.setDynamicShortcuts(list()));
Log.i(TAG, "Saved state");
@@ -4074,7 +4074,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
assertNull(ShortcutPackage.loadFromFile(mService, user, corruptedShortcutPackage, false));
}
- public void testSaveCorruptAndLoadUser() throws Exception {
+ public void disabled_testSaveCorruptAndLoadUser() throws Exception {
// First, create some shortcuts and save.
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.black_64x16);
@@ -6658,7 +6658,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
}
- public void testSaveAndLoad_crossProfile() {
+ public void disabled_testSaveAndLoad_crossProfile() {
prepareCrossProfileDataSet();
dumpsysOnLogcat("Before save & load");
@@ -8471,7 +8471,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
});
}
- public void testShortcutsPushedOutByManifest() {
+ public void disabled_testShortcutsPushedOutByManifest() {
// Change the max number of shortcuts.
mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=3");
@@ -8708,7 +8708,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
}
}
- public void testShareTargetInfo_saveToXml() throws IOException, XmlPullParserException {
+ public void disabled_testShareTargetInfo_saveToXml() throws IOException, XmlPullParserException {
List<ShareTargetInfo> expectedValues = new ArrayList<>();
expectedValues.add(new ShareTargetInfo(
new ShareTargetInfo.TargetData[]{new ShareTargetInfo.TargetData(
@@ -8902,7 +8902,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
});
}
- public void testUpdateShortcuts_ExcludesHiddenFromLauncherShortcuts() {
+ public void disabled_testUpdateShortcuts_ExcludesHiddenFromLauncherShortcuts() {
final ShortcutInfo s1 = makeShortcut("s1");
final ShortcutInfo s2 = makeShortcut("s2");
final ShortcutInfo s3 = makeShortcut("s3");
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 9528467f7ad1..39206dcf21ef 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -952,7 +952,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
assertEquals(99, si.getExtras().getInt("x"));
}
- public void testShortcutInfoSaveAndLoad() throws InterruptedException {
+ public void disabled_testShortcutInfoSaveAndLoad() throws InterruptedException {
mRunningUsers.put(USER_11, true);
setCaller(CALLING_PACKAGE_1, USER_11);
@@ -1065,7 +1065,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
dumpUserFile(USER_11);
}
- public void testShortcutInfoSaveAndLoad_maskableBitmap() throws InterruptedException {
+ public void disabled_testShortcutInfoSaveAndLoad_maskableBitmap() throws InterruptedException {
mRunningUsers.put(USER_11, true);
setCaller(CALLING_PACKAGE_1, USER_11);
@@ -1134,7 +1134,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
dumpUserFile(USER_11);
}
- public void testShortcutInfoSaveAndLoad_resId() throws InterruptedException {
+ public void disabled_testShortcutInfoSaveAndLoad_resId() throws InterruptedException {
mRunningUsers.put(USER_11, true);
setCaller(CALLING_PACKAGE_1, USER_11);
@@ -1211,7 +1211,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
assertEquals(1, si.getRank());
}
- public void testShortcutInfoSaveAndLoad_uri() throws InterruptedException {
+ public void disabled_testShortcutInfoSaveAndLoad_uri() throws InterruptedException {
mRunningUsers.put(USER_11, true);
setCaller(CALLING_PACKAGE_1, USER_11);
@@ -1299,7 +1299,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
assertEquals("uri_maskable", si.getIconUri());
}
- public void testShortcutInfoSaveAndLoad_forBackup() {
+ public void disabled_testShortcutInfoSaveAndLoad_forBackup() {
setCaller(CALLING_PACKAGE_1, USER_10);
final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
@@ -1368,7 +1368,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
assertEquals(0, si.getRank());
}
- public void testShortcutInfoSaveAndLoad_forBackup_resId() {
+ public void disabled_testShortcutInfoSaveAndLoad_forBackup_resId() {
setCaller(CALLING_PACKAGE_1, USER_10);
final Icon res32x32 = Icon.createWithResource(mClientContext, R.drawable.black_32x32);
@@ -1438,7 +1438,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
assertEquals(0, si.getRank());
}
- public void testShortcutInfoSaveAndLoad_forBackup_uri() {
+ public void disabled_testShortcutInfoSaveAndLoad_forBackup_uri() {
setCaller(CALLING_PACKAGE_1, USER_10);
final Icon uriIcon = Icon.createWithContentUri("test_uri");
@@ -1547,7 +1547,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
});
}
- public void testShortcutInfoSaveAndLoad_intents() {
+ public void disabled_testShortcutInfoSaveAndLoad_intents() {
checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_VIEW));
mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
@@ -1789,7 +1789,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
assertFalse(mManager.setDynamicShortcuts(list(si2)));
}
- public void testThrottling_localeChanges() {
+ public void disabled_testThrottling_localeChanges() {
prepareCrossProfileDataSet();
dumpsysOnLogcat("Before save & load");
@@ -2078,7 +2078,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
}
- public void testThrottling_resetByInternalCall() throws Exception {
+ public void disabled_testThrottling_resetByInternalCall() throws Exception {
prepareCrossProfileDataSet();
dumpsysOnLogcat("Before save & load");
@@ -2173,7 +2173,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
});
}
- public void testReportShortcutUsed() {
+ public void disabled_testReportShortcutUsed() {
mRunningUsers.put(USER_11, true);
runWithCaller(CALLING_PACKAGE_1, USER_11, () -> {
@@ -2322,7 +2322,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
getTestContext().getPackageName()));
}
- public void testDumpCheckin() throws IOException {
+ public void disabled_testDumpCheckin() throws IOException {
prepareCrossProfileDataSet();
// prepareCrossProfileDataSet() doesn't set any icons, so do set here.
diff --git a/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
index 551808243640..7f2935e0e497 100644
--- a/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
@@ -18,6 +18,7 @@ package com.android.server.policy;
import static android.content.Context.SENSOR_SERVICE;
+import static android.hardware.devicestate.feature.flags.Flags.FLAG_DEVICE_STATE_CONFIGURATION_FLAG;
import static com.android.server.devicestate.DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED;
import static com.android.server.devicestate.DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_DISABLED;
@@ -42,6 +43,9 @@ import android.hardware.SensorEvent;
import android.hardware.SensorManager;
import android.hardware.devicestate.DeviceState;
import android.os.PowerManager;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.annotation.NonNull;
@@ -51,6 +55,7 @@ import com.android.server.input.InputManagerInternal;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
@@ -84,6 +89,10 @@ public final class DeviceStateProviderImplTest {
private Context mContext;
private SensorManager mSensorManager;
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule =
+ DeviceFlagsValueProvider.createCheckFlagsRule();
+
@Before
public void setup() {
LocalServices.addService(InputManagerInternal.class, mock(InputManagerInternal.class));
@@ -605,6 +614,37 @@ public final class DeviceStateProviderImplTest {
verify(listener, never()).onStateChanged(mIntegerCaptor.capture());
}
+ @RequiresFlagsEnabled(FLAG_DEVICE_STATE_CONFIGURATION_FLAG)
+ @Test
+ public void test_createConfigWithFlags() {
+ String configString = "<device-state-config>\n"
+ + " <device-state>\n"
+ + " <identifier>1</identifier>\n"
+ + " <flags>\n"
+ + " <flag>FLAG_CANCEL_OVERRIDE_REQUESTS</flag>\n"
+ + " </flags>\n"
+ + " </device-state>\n"
+ + " <device-state>\n"
+ + " <identifier>2</identifier>\n"
+ + " <name>CLOSED</name>\n"
+ + " </device-state>\n"
+ + "</device-state-config>\n";
+ DeviceStateProviderImpl.ReadableConfig config = new TestReadableConfig(configString);
+ DeviceStateProviderImpl provider = DeviceStateProviderImpl.createFromConfig(mContext,
+ config);
+
+ DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class);
+ provider.setListener(listener);
+
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
+ final DeviceState[] expectedStates = new DeviceState[]{
+ createDeviceState(1, "",
+ Set.of(DeviceState.PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS)),
+ createDeviceState(2, "CLOSED", EMPTY_PROPERTY_SET)};
+ assertArrayEquals(expectedStates, mDeviceStateArrayCaptor.getValue());
+ }
+
private DeviceState createDeviceState(int identifier, @NonNull String name,
@NonNull Set<@DeviceState.DeviceStateProperties Integer> systemProperties) {
DeviceState.Configuration configuration = new DeviceState.Configuration.Builder(identifier,
diff --git a/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/AuthenticationPolicyServiceTest.java b/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/AuthenticationPolicyServiceTest.java
index ee8eb9b35088..b76e0bc8cd14 100644
--- a/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/AuthenticationPolicyServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/AuthenticationPolicyServiceTest.java
@@ -42,8 +42,10 @@ import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.events.AuthenticationFailedInfo;
import android.hardware.biometrics.events.AuthenticationSucceededInfo;
import android.os.RemoteException;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
+import android.provider.Settings;
import androidx.test.InstrumentationRegistry;
import androidx.test.core.app.ApplicationProvider;
@@ -151,6 +153,8 @@ public class AuthenticationPolicyServiceTest {
when(mSecureLockDeviceService.disableSecureLockDevice(any()))
.thenReturn(ERROR_UNSUPPORTED);
}
+
+ toggleAdaptiveAuthSettingsOverride(PRIMARY_USER_ID, false /* disable */);
}
@After
@@ -252,8 +256,24 @@ public class AuthenticationPolicyServiceTest {
}
@Test
- public void testReportAuthAttempt_biometricAuthFailed_multiple_deviceCurrentlyNotLocked()
+ @EnableFlags({android.security.Flags.FLAG_DISABLE_ADAPTIVE_AUTH_COUNTER_LOCK})
+ public void testReportAuthAttempt_biometricAuthFailed_multiple_deviceCurrentlyNotLocked_deviceLockEnabled()
+ throws RemoteException {
+ testReportAuthAttempt_biometricAuthFailed_multiple_deviceCurrentlyNotLocked(
+ true /* enabled */);
+ }
+
+ @Test
+ @EnableFlags({android.security.Flags.FLAG_DISABLE_ADAPTIVE_AUTH_COUNTER_LOCK})
+ public void testReportAuthAttempt_biometricAuthFailed_multiple_deviceCurrentlyNotLocked_deviceLockDisabled()
throws RemoteException {
+ toggleAdaptiveAuthSettingsOverride(PRIMARY_USER_ID, true /* disabled */);
+ testReportAuthAttempt_biometricAuthFailed_multiple_deviceCurrentlyNotLocked(
+ false /* enabled */);
+ }
+
+ private void testReportAuthAttempt_biometricAuthFailed_multiple_deviceCurrentlyNotLocked(
+ boolean enabled) throws RemoteException {
// Device is currently not locked and Keyguard is not showing
when(mKeyguardManager.isDeviceLocked(PRIMARY_USER_ID)).thenReturn(false);
when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
@@ -264,7 +284,11 @@ public class AuthenticationPolicyServiceTest {
}
waitForAuthCompletion();
- verifyLockDevice(PRIMARY_USER_ID);
+ if (enabled) {
+ verifyLockDevice(PRIMARY_USER_ID);
+ } else {
+ verifyNotLockDevice(MAX_ALLOWED_FAILED_AUTH_ATTEMPTS, PRIMARY_USER_ID);
+ }
}
@Test
@@ -300,8 +324,24 @@ public class AuthenticationPolicyServiceTest {
}
@Test
- public void testReportAuthAttempt_primaryAuthAndBiometricAuthFailed_primaryUser()
+ @EnableFlags({android.security.Flags.FLAG_DISABLE_ADAPTIVE_AUTH_COUNTER_LOCK})
+ public void testReportAuthAttempt_primaryAuthAndBiometricAuthFailed_primaryUser_deviceLockEnabled()
throws RemoteException {
+ testReportAuthAttempt_primaryAuthAndBiometricAuthFailed_primaryUser(
+ true /* enabled */);
+ }
+
+ @Test
+ @EnableFlags({android.security.Flags.FLAG_DISABLE_ADAPTIVE_AUTH_COUNTER_LOCK})
+ public void testReportAuthAttempt_primaryAuthAndBiometricAuthFailed_primaryUser_deviceLockDisabled()
+ throws RemoteException {
+ toggleAdaptiveAuthSettingsOverride(PRIMARY_USER_ID, true /* disabled */);
+ testReportAuthAttempt_primaryAuthAndBiometricAuthFailed_primaryUser(
+ false /* enabled */);
+ }
+
+ private void testReportAuthAttempt_primaryAuthAndBiometricAuthFailed_primaryUser(
+ boolean enabled) throws RemoteException {
// Three failed primary auth attempts
for (int i = 0; i < 3; i++) {
mLockSettingsStateListenerCaptor.getValue().onAuthenticationFailed(PRIMARY_USER_ID);
@@ -313,7 +353,11 @@ public class AuthenticationPolicyServiceTest {
}
waitForAuthCompletion();
- verifyLockDevice(PRIMARY_USER_ID);
+ if (enabled) {
+ verifyLockDevice(PRIMARY_USER_ID);
+ } else {
+ verifyNotLockDevice(MAX_ALLOWED_FAILED_AUTH_ATTEMPTS, PRIMARY_USER_ID);
+ }
}
@Test
@@ -366,10 +410,13 @@ public class AuthenticationPolicyServiceTest {
REASON_UNKNOWN, true, userId).build();
}
-
private AuthenticationFailedInfo authFailedInfo(int userId) {
return new AuthenticationFailedInfo.Builder(BiometricSourceType.FINGERPRINT, REASON_UNKNOWN,
userId).build();
}
+ private void toggleAdaptiveAuthSettingsOverride(int userId, boolean disable) {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.DISABLE_ADAPTIVE_AUTH_LIMIT_LOCK, disable ? 1 : 0, userId);
+ }
}
diff --git a/services/tests/timetests/src/com/android/server/timezonedetector/FakeEnvironment.java b/services/tests/timetests/src/com/android/server/timezonedetector/FakeEnvironment.java
new file mode 100644
index 000000000000..5d181b81eb4c
--- /dev/null
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/FakeEnvironment.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.timezonedetector;
+
+import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_LOW;
+
+import android.annotation.CurrentTimeMillisLong;
+import android.annotation.ElapsedRealtimeLong;
+
+import com.android.server.SystemTimeZone;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A partially implemented, fake implementation of Environment for tests.
+ */
+public class FakeEnvironment implements Environment {
+
+ private final TestState<String> mTimeZoneId = new TestState<>();
+ private final TestState<Integer> mTimeZoneConfidence = new TestState<>();
+ private final List<Runnable> mAsyncRunnables = new ArrayList<>();
+ private @ElapsedRealtimeLong long mElapsedRealtimeMillis;
+ private @CurrentTimeMillisLong long mInitializationTimeMillis;
+
+ FakeEnvironment() {
+ // Ensure the fake environment starts with the defaults a fresh device would.
+ initializeTimeZoneSetting("", TIME_ZONE_CONFIDENCE_LOW);
+ }
+
+ void initializeClock(@CurrentTimeMillisLong long currentTimeMillis,
+ @ElapsedRealtimeLong long elapsedRealtimeMillis) {
+ mInitializationTimeMillis = currentTimeMillis - elapsedRealtimeMillis;
+ mElapsedRealtimeMillis = elapsedRealtimeMillis;
+ }
+
+ void initializeTimeZoneSetting(String zoneId,
+ @SystemTimeZone.TimeZoneConfidence int timeZoneConfidence) {
+ mTimeZoneId.init(zoneId);
+ mTimeZoneConfidence.init(timeZoneConfidence);
+ }
+
+ void incrementClock() {
+ mElapsedRealtimeMillis++;
+ }
+
+ @Override
+ public String getDeviceTimeZone() {
+ return mTimeZoneId.getLatest();
+ }
+
+ @Override
+ public int getDeviceTimeZoneConfidence() {
+ return mTimeZoneConfidence.getLatest();
+ }
+
+ @Override
+ public void setDeviceTimeZoneAndConfidence(
+ String zoneId, @SystemTimeZone.TimeZoneConfidence int confidence, String logInfo) {
+ mTimeZoneId.set(zoneId);
+ mTimeZoneConfidence.set(confidence);
+ }
+
+ void assertTimeZoneNotChanged() {
+ mTimeZoneId.assertHasNotBeenSet();
+ mTimeZoneConfidence.assertHasNotBeenSet();
+ }
+
+ void assertTimeZoneChangedTo(String timeZoneId,
+ @SystemTimeZone.TimeZoneConfidence int confidence) {
+ mTimeZoneId.assertHasBeenSet();
+ mTimeZoneId.assertChangeCount(1);
+ mTimeZoneId.assertLatestEquals(timeZoneId);
+
+ mTimeZoneConfidence.assertHasBeenSet();
+ mTimeZoneConfidence.assertChangeCount(1);
+ mTimeZoneConfidence.assertLatestEquals(confidence);
+ }
+
+ void commitAllChanges() {
+ mTimeZoneId.commitLatest();
+ mTimeZoneConfidence.commitLatest();
+ }
+
+ @Override
+ @ElapsedRealtimeLong
+ public long elapsedRealtimeMillis() {
+ return mElapsedRealtimeMillis;
+ }
+
+ @Override
+ @CurrentTimeMillisLong
+ public long currentTimeMillis() {
+ return mInitializationTimeMillis + mElapsedRealtimeMillis;
+ }
+
+ @Override
+ public void addDebugLogEntry(String logMsg) {
+ // No-op for tests
+ }
+
+ @Override
+ public void dumpDebugLog(PrintWriter printWriter) {
+ // No-op for tests
+ }
+
+ /**
+ * Adds the supplied runnable to a list but does not run them. To run all the runnables that
+ * have been supplied, call {@code #runAsyncRunnables}.
+ */
+ @Override
+ public void runAsync(Runnable runnable) {
+ mAsyncRunnables.add(runnable);
+ }
+
+ /**
+ * Requests that the runnable that have been supplied to {@code #runAsync} are invoked
+ * asynchronously and cleared.
+ */
+ public void runAsyncRunnables() {
+ for (Runnable runnable : mAsyncRunnables) {
+ runnable.run();
+ }
+ mAsyncRunnables.clear();
+ }
+}
diff --git a/services/tests/timetests/src/com/android/server/timezonedetector/NotifyingTimeZoneChangeListenerTest.java b/services/tests/timetests/src/com/android/server/timezonedetector/NotifyingTimeZoneChangeListenerTest.java
index 23c13bd04368..45cc891bff55 100644
--- a/services/tests/timetests/src/com/android/server/timezonedetector/NotifyingTimeZoneChangeListenerTest.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/NotifyingTimeZoneChangeListenerTest.java
@@ -85,9 +85,6 @@ public class NotifyingTimeZoneChangeListenerTest {
return List.of(ORIGIN_LOCATION, ORIGIN_TELEPHONY);
}
- private static final long ARBITRARY_ELAPSED_REALTIME_MILLIS = 1234;
- /** A time zone used for initialization that does not occur elsewhere in tests. */
- private static final String ARBITRARY_TIME_ZONE_ID = "Etc/UTC";
private static final String INTERACT_ACROSS_USERS_FULL_PERMISSION =
"android.permission.INTERACT_ACROSS_USERS_FULL";
@@ -99,6 +96,7 @@ public class NotifyingTimeZoneChangeListenerTest {
private HandlerThread mHandlerThread;
private TestHandler mHandler;
private FakeServiceConfigAccessor mServiceConfigAccessor;
+ private FakeEnvironment mFakeEnvironment;
private int mUid;
private NotifyingTimeZoneChangeListener mTimeZoneChangeTracker;
@@ -106,6 +104,9 @@ public class NotifyingTimeZoneChangeListenerTest {
@Before
public void setUp() {
mUid = Process.myUid();
+ mFakeEnvironment = new FakeEnvironment();
+ mFakeEnvironment.initializeClock(1735689600L, 1234L);
+
// Create a thread + handler for processing the work that the service posts.
mHandlerThread = new HandlerThread("TimeZoneDetectorInternalTest");
mHandlerThread.start();
@@ -138,7 +139,7 @@ public class NotifyingTimeZoneChangeListenerTest {
mNotificationManager = new FakeNotificationManager(mContext, InstantSource.system());
mTimeZoneChangeTracker = new NotifyingTimeZoneChangeListener(mHandler, mContext,
- mServiceConfigAccessor, mNotificationManager);
+ mServiceConfigAccessor, mNotificationManager, mFakeEnvironment);
}
@After
@@ -151,7 +152,7 @@ public class NotifyingTimeZoneChangeListenerTest {
public void process_autoDetectionOff_noManualTracking_shouldTrackWithoutNotifying() {
enableTimeZoneNotifications();
- TimeZoneChangeRecord expectedChangeEvent = new TimeZoneChangeRecord(
+ TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord(
/* id= */ 1,
new TimeZoneChangeEvent(
/* elapsedRealtimeMillis= */ 0,
@@ -162,13 +163,14 @@ public class NotifyingTimeZoneChangeListenerTest {
/* newZoneId= */ "Europe/London",
/* newConfidence= */ 1,
/* cause= */ "NO_REASON"));
- expectedChangeEvent.setStatus(STATUS_UNTRACKED, SIGNAL_TYPE_NONE);
+ expectedTimeZoneChangeRecord.setStatus(STATUS_UNTRACKED, SIGNAL_TYPE_NONE);
assertNull(mTimeZoneChangeTracker.getLastTimeZoneChangeRecord());
- mTimeZoneChangeTracker.process(expectedChangeEvent.getEvent());
+ mTimeZoneChangeTracker.process(expectedTimeZoneChangeRecord.getEvent());
- assertEquals(expectedChangeEvent, mTimeZoneChangeTracker.getLastTimeZoneChangeRecord());
+ assertEquals(expectedTimeZoneChangeRecord,
+ mTimeZoneChangeTracker.getLastTimeZoneChangeRecord());
assertEquals(0, mNotificationManager.getNotifications().size());
mHandler.assertTotalMessagesEnqueued(0);
}
@@ -177,7 +179,7 @@ public class NotifyingTimeZoneChangeListenerTest {
public void process_autoDetectionOff_shouldTrackWithoutNotifying() {
enableNotificationsWithManualChangeTracking();
- TimeZoneChangeRecord expectedChangeEvent = new TimeZoneChangeRecord(
+ TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord(
/* id= */ 1,
new TimeZoneChangeEvent(
/* elapsedRealtimeMillis= */ 0,
@@ -188,13 +190,14 @@ public class NotifyingTimeZoneChangeListenerTest {
/* newZoneId= */ "Europe/London",
/* newConfidence= */ 1,
/* cause= */ "NO_REASON"));
- expectedChangeEvent.setStatus(STATUS_UNTRACKED, SIGNAL_TYPE_NONE);
+ expectedTimeZoneChangeRecord.setStatus(STATUS_UNTRACKED, SIGNAL_TYPE_NONE);
assertNull(mTimeZoneChangeTracker.getLastTimeZoneChangeRecord());
- mTimeZoneChangeTracker.process(expectedChangeEvent.getEvent());
+ mTimeZoneChangeTracker.process(expectedTimeZoneChangeRecord.getEvent());
- assertEquals(expectedChangeEvent, mTimeZoneChangeTracker.getLastTimeZoneChangeRecord());
+ assertEquals(expectedTimeZoneChangeRecord,
+ mTimeZoneChangeTracker.getLastTimeZoneChangeRecord());
assertEquals(0, mNotificationManager.getNotifications().size());
mHandler.assertTotalMessagesEnqueued(1);
}
@@ -214,7 +217,7 @@ public class NotifyingTimeZoneChangeListenerTest {
enableNotificationsWithManualChangeTracking();
- TimeZoneChangeRecord expectedChangeEvent = new TimeZoneChangeRecord(
+ TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord(
/* id= */ 1,
new TimeZoneChangeEvent(
/* elapsedRealtimeMillis= */ 0,
@@ -225,19 +228,20 @@ public class NotifyingTimeZoneChangeListenerTest {
/* newZoneId= */ "Europe/London",
/* newConfidence= */ 1,
/* cause= */ "NO_REASON"));
- expectedChangeEvent.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN);
+ expectedTimeZoneChangeRecord.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN);
assertNull(mTimeZoneChangeTracker.getLastTimeZoneChangeRecord());
// lastTrackedChangeEvent == null
- mTimeZoneChangeTracker.process(expectedChangeEvent.getEvent());
- TimeZoneChangeRecord trackedEvent1 = mTimeZoneChangeTracker.getLastTimeZoneChangeRecord();
+ mTimeZoneChangeTracker.process(expectedTimeZoneChangeRecord.getEvent());
+ TimeZoneChangeRecord timeZoneChangeRecord1 =
+ mTimeZoneChangeTracker.getLastTimeZoneChangeRecord();
- assertEquals(expectedChangeEvent, trackedEvent1);
+ assertEquals(expectedTimeZoneChangeRecord, timeZoneChangeRecord1);
assertEquals(1, mNotificationManager.getNotifications().size());
mHandler.assertTotalMessagesEnqueued(1);
- expectedChangeEvent = new TimeZoneChangeRecord(
+ expectedTimeZoneChangeRecord = new TimeZoneChangeRecord(
/* id= */ 2,
new TimeZoneChangeEvent(
/* elapsedRealtimeMillis= */ 1000L,
@@ -248,14 +252,15 @@ public class NotifyingTimeZoneChangeListenerTest {
/* newZoneId= */ "Europe/Paris",
/* newConfidence= */ 1,
/* cause= */ "NO_REASON"));
- expectedChangeEvent.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN);
+ expectedTimeZoneChangeRecord.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN);
// lastTrackedChangeEvent != null
- mTimeZoneChangeTracker.process(expectedChangeEvent.getEvent());
- TimeZoneChangeRecord trackedEvent2 = mTimeZoneChangeTracker.getLastTimeZoneChangeRecord();
+ mTimeZoneChangeTracker.process(expectedTimeZoneChangeRecord.getEvent());
+ TimeZoneChangeRecord timeZoneChangeRecord2 =
+ mTimeZoneChangeTracker.getLastTimeZoneChangeRecord();
- assertEquals(STATUS_SUPERSEDED, trackedEvent1.getStatus());
- assertEquals(expectedChangeEvent, trackedEvent2);
+ assertEquals(STATUS_SUPERSEDED, timeZoneChangeRecord1.getStatus());
+ assertEquals(expectedTimeZoneChangeRecord, timeZoneChangeRecord2);
assertEquals(2, mNotificationManager.getNotifications().size());
mHandler.assertTotalMessagesEnqueued(2);
@@ -263,7 +268,7 @@ public class NotifyingTimeZoneChangeListenerTest {
// Test manual change within revert threshold
{
- expectedChangeEvent = new TimeZoneChangeRecord(
+ expectedTimeZoneChangeRecord = new TimeZoneChangeRecord(
/* id= */ 3,
new TimeZoneChangeEvent(
/* elapsedRealtimeMillis= */ 999L + AUTO_REVERT_THRESHOLD,
@@ -275,16 +280,16 @@ public class NotifyingTimeZoneChangeListenerTest {
/* newZoneId= */ "Europe/London",
/* newConfidence= */ 1,
/* cause= */ "NO_REASON"));
- expectedChangeEvent.setStatus(STATUS_UNTRACKED, SIGNAL_TYPE_NONE);
+ expectedTimeZoneChangeRecord.setStatus(STATUS_UNTRACKED, SIGNAL_TYPE_NONE);
- mTimeZoneChangeTracker.process(expectedChangeEvent.getEvent());
- TimeZoneChangeRecord trackedEvent3 =
+ mTimeZoneChangeTracker.process(expectedTimeZoneChangeRecord.getEvent());
+ TimeZoneChangeRecord timeZoneChangeRecord3 =
mTimeZoneChangeTracker.getLastTimeZoneChangeRecord();
// The user manually changed the time zone within a short period of receiving the
// notification, indicating that they rejected the automatic change of time zone
- assertEquals(STATUS_REJECTED, trackedEvent2.getStatus());
- assertEquals(expectedChangeEvent, trackedEvent3);
+ assertEquals(STATUS_REJECTED, timeZoneChangeRecord2.getStatus());
+ assertEquals(expectedTimeZoneChangeRecord, timeZoneChangeRecord3);
assertEquals(2, mNotificationManager.getNotifications().size());
mHandler.assertTotalMessagesEnqueued(3);
}
@@ -293,12 +298,12 @@ public class NotifyingTimeZoneChangeListenerTest {
{
// [START] Reset previous event
enableNotificationsWithManualChangeTracking();
- mTimeZoneChangeTracker.process(trackedEvent2.getEvent());
- trackedEvent2 = mTimeZoneChangeTracker.getLastTimeZoneChangeRecord();
+ mTimeZoneChangeTracker.process(timeZoneChangeRecord2.getEvent());
+ timeZoneChangeRecord2 = mTimeZoneChangeTracker.getLastTimeZoneChangeRecord();
disableTimeZoneAutoDetection();
// [END] Reset previous event
- expectedChangeEvent = new TimeZoneChangeRecord(
+ expectedTimeZoneChangeRecord = new TimeZoneChangeRecord(
/* id= */ 5,
new TimeZoneChangeEvent(
/* elapsedRealtimeMillis= */ 1001L + AUTO_REVERT_THRESHOLD,
@@ -310,15 +315,15 @@ public class NotifyingTimeZoneChangeListenerTest {
/* newZoneId= */ "Europe/London",
/* newConfidence= */ 1,
/* cause= */ "NO_REASON"));
- expectedChangeEvent.setStatus(STATUS_UNTRACKED, SIGNAL_TYPE_NONE);
+ expectedTimeZoneChangeRecord.setStatus(STATUS_UNTRACKED, SIGNAL_TYPE_NONE);
- mTimeZoneChangeTracker.process(expectedChangeEvent.getEvent());
- TimeZoneChangeRecord trackedEvent3 =
+ mTimeZoneChangeTracker.process(expectedTimeZoneChangeRecord.getEvent());
+ TimeZoneChangeRecord timeZoneChangeRecord3 =
mTimeZoneChangeTracker.getLastTimeZoneChangeRecord();
// The user manually changed the time zone outside of the period we consider as a revert
- assertEquals(STATUS_SUPERSEDED, trackedEvent2.getStatus());
- assertEquals(expectedChangeEvent, trackedEvent3);
+ assertEquals(STATUS_SUPERSEDED, timeZoneChangeRecord2.getStatus());
+ assertEquals(expectedTimeZoneChangeRecord, timeZoneChangeRecord3);
assertEquals(3, mNotificationManager.getNotifications().size());
mHandler.assertTotalMessagesEnqueued(5);
}
@@ -339,7 +344,7 @@ public class NotifyingTimeZoneChangeListenerTest {
enableNotificationsWithManualChangeTracking();
- TimeZoneChangeRecord expectedChangeEvent = new TimeZoneChangeRecord(
+ TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord(
/* id= */ 1,
new TimeZoneChangeEvent(
/* elapsedRealtimeMillis= */ 0,
@@ -350,19 +355,20 @@ public class NotifyingTimeZoneChangeListenerTest {
/* newZoneId= */ "Europe/London",
/* newConfidence= */ 1,
/* cause= */ "NO_REASON"));
- expectedChangeEvent.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN);
+ expectedTimeZoneChangeRecord.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN);
assertNull(mTimeZoneChangeTracker.getLastTimeZoneChangeRecord());
// lastTrackedChangeEvent == null
- mTimeZoneChangeTracker.process(expectedChangeEvent.getEvent());
- TimeZoneChangeRecord trackedEvent1 = mTimeZoneChangeTracker.getLastTimeZoneChangeRecord();
+ mTimeZoneChangeTracker.process(expectedTimeZoneChangeRecord.getEvent());
+ TimeZoneChangeRecord timeZoneChangeRecord1 =
+ mTimeZoneChangeTracker.getLastTimeZoneChangeRecord();
- assertEquals(expectedChangeEvent, trackedEvent1);
+ assertEquals(expectedTimeZoneChangeRecord, timeZoneChangeRecord1);
assertEquals(1, mNotificationManager.getNotifications().size());
mHandler.assertTotalMessagesEnqueued(1);
- expectedChangeEvent = new TimeZoneChangeRecord(
+ expectedTimeZoneChangeRecord = new TimeZoneChangeRecord(
/* id= */ 3,
new TimeZoneChangeEvent(
/* elapsedRealtimeMillis= */ 1000L,
@@ -373,14 +379,15 @@ public class NotifyingTimeZoneChangeListenerTest {
/* newZoneId= */ "Europe/Paris",
/* newConfidence= */ 1,
/* cause= */ "NO_REASON"));
- expectedChangeEvent.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN);
+ expectedTimeZoneChangeRecord.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN);
// lastTrackedChangeEvent != null
- mTimeZoneChangeTracker.process(expectedChangeEvent.getEvent());
- TimeZoneChangeRecord trackedEvent2 = mTimeZoneChangeTracker.getLastTimeZoneChangeRecord();
+ mTimeZoneChangeTracker.process(expectedTimeZoneChangeRecord.getEvent());
+ TimeZoneChangeRecord timeZoneChangeRecord2 =
+ mTimeZoneChangeTracker.getLastTimeZoneChangeRecord();
- assertEquals(STATUS_SUPERSEDED, trackedEvent1.getStatus());
- assertEquals(expectedChangeEvent, trackedEvent2);
+ assertEquals(STATUS_SUPERSEDED, timeZoneChangeRecord1.getStatus());
+ assertEquals(expectedTimeZoneChangeRecord, timeZoneChangeRecord2);
assertEquals(2, mNotificationManager.getNotifications().size());
mHandler.assertTotalMessagesEnqueued(2);
}
@@ -400,7 +407,7 @@ public class NotifyingTimeZoneChangeListenerTest {
enableNotificationsWithManualChangeTracking();
- TimeZoneChangeRecord expectedChangeEvent = new TimeZoneChangeRecord(
+ TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord(
/* id= */ 1,
new TimeZoneChangeEvent(
/* elapsedRealtimeMillis= */ 0,
@@ -411,15 +418,16 @@ public class NotifyingTimeZoneChangeListenerTest {
/* newZoneId= */ "Europe/Rome",
/* newConfidence= */ 1,
/* cause= */ "NO_REASON"));
- expectedChangeEvent.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN);
+ expectedTimeZoneChangeRecord.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN);
assertNull(mTimeZoneChangeTracker.getLastTimeZoneChangeRecord());
// lastTrackedChangeEvent == null
- mTimeZoneChangeTracker.process(expectedChangeEvent.getEvent());
- TimeZoneChangeRecord trackedEvent1 = mTimeZoneChangeTracker.getLastTimeZoneChangeRecord();
+ mTimeZoneChangeTracker.process(expectedTimeZoneChangeRecord.getEvent());
+ TimeZoneChangeRecord timeZoneChangeRecord1 =
+ mTimeZoneChangeTracker.getLastTimeZoneChangeRecord();
- assertEquals(expectedChangeEvent, trackedEvent1);
+ assertEquals(expectedTimeZoneChangeRecord, timeZoneChangeRecord1);
// No notification sent for the same UTC offset
assertEquals(0, mNotificationManager.getNotifications().size());
mHandler.assertTotalMessagesEnqueued(1);
diff --git a/services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index 9a01fa2eb966..44232e7ddfa2 100644
--- a/services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -63,7 +63,6 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.time.LocationTimeZoneAlgorithmStatus;
@@ -94,7 +93,6 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -114,6 +112,7 @@ public class TimeZoneDetectorStrategyImplTest {
@Rule
public final SetFlagsRule mSetFlagsRule = mClassRule.createSetFlagsRule();
+ private static final long ARBITRARY_CURRENT_TIME_MILLIS = 1735689600; // 2025-01-01 00:00:00
private static final long ARBITRARY_ELAPSED_REALTIME_MILLIS = 1234;
/** A time zone used for initialization that does not occur elsewhere in tests. */
private static final String ARBITRARY_TIME_ZONE_ID = "Etc/UTC";
@@ -1220,7 +1219,7 @@ public class TimeZoneDetectorStrategyImplTest {
.build();
Script script = new Script()
- .initializeClock(ARBITRARY_ELAPSED_REALTIME_MILLIS)
+ .initializeClock(ARBITRARY_CURRENT_TIME_MILLIS, ARBITRARY_ELAPSED_REALTIME_MILLIS)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID, TIME_ZONE_CONFIDENCE_LOW)
.simulateConfigurationInternalChange(config)
.resetConfigurationTracking();
@@ -1420,7 +1419,7 @@ public class TimeZoneDetectorStrategyImplTest {
.build();
Script script = new Script()
- .initializeClock(ARBITRARY_ELAPSED_REALTIME_MILLIS)
+ .initializeClock(ARBITRARY_CURRENT_TIME_MILLIS, ARBITRARY_ELAPSED_REALTIME_MILLIS)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID, TIME_ZONE_CONFIDENCE_LOW)
.simulateConfigurationInternalChange(config)
.resetConfigurationTracking();
@@ -1591,7 +1590,7 @@ public class TimeZoneDetectorStrategyImplTest {
.build();
Script script = new Script()
- .initializeClock(ARBITRARY_ELAPSED_REALTIME_MILLIS)
+ .initializeClock(ARBITRARY_CURRENT_TIME_MILLIS, ARBITRARY_ELAPSED_REALTIME_MILLIS)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID, TIME_ZONE_CONFIDENCE_LOW)
.simulateConfigurationInternalChange(config)
.resetConfigurationTracking();
@@ -1666,7 +1665,7 @@ public class TimeZoneDetectorStrategyImplTest {
@Test
public void testGetTimeZoneState() {
Script script = new Script()
- .initializeClock(ARBITRARY_ELAPSED_REALTIME_MILLIS)
+ .initializeClock(ARBITRARY_CURRENT_TIME_MILLIS, ARBITRARY_ELAPSED_REALTIME_MILLIS)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID, TIME_ZONE_CONFIDENCE_LOW)
.simulateConfigurationInternalChange(CONFIG_AUTO_DISABLED_GEO_DISABLED)
.resetConfigurationTracking();
@@ -1688,7 +1687,7 @@ public class TimeZoneDetectorStrategyImplTest {
@Test
public void testSetTimeZoneState() {
Script script = new Script()
- .initializeClock(ARBITRARY_ELAPSED_REALTIME_MILLIS)
+ .initializeClock(ARBITRARY_CURRENT_TIME_MILLIS, ARBITRARY_ELAPSED_REALTIME_MILLIS)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID, TIME_ZONE_CONFIDENCE_LOW)
.simulateConfigurationInternalChange(CONFIG_AUTO_DISABLED_GEO_DISABLED)
.resetConfigurationTracking();
@@ -1715,7 +1714,7 @@ public class TimeZoneDetectorStrategyImplTest {
private void testConfirmTimeZone(ConfigurationInternal config) {
String timeZoneId = "Europe/London";
Script script = new Script()
- .initializeClock(ARBITRARY_ELAPSED_REALTIME_MILLIS)
+ .initializeClock(ARBITRARY_CURRENT_TIME_MILLIS, ARBITRARY_ELAPSED_REALTIME_MILLIS)
.initializeTimeZoneSetting(timeZoneId, TIME_ZONE_CONFIDENCE_LOW)
.simulateConfigurationInternalChange(config)
.resetConfigurationTracking();
@@ -1902,97 +1901,6 @@ public class TimeZoneDetectorStrategyImplTest {
mFakeEnvironment.elapsedRealtimeMillis(), Arrays.asList(zoneIds));
}
- static class FakeEnvironment implements TimeZoneDetectorStrategyImpl.Environment {
-
- private final TestState<String> mTimeZoneId = new TestState<>();
- private final TestState<Integer> mTimeZoneConfidence = new TestState<>();
- private final List<Runnable> mAsyncRunnables = new ArrayList<>();
- private @ElapsedRealtimeLong long mElapsedRealtimeMillis;
-
- FakeEnvironment() {
- // Ensure the fake environment starts with the defaults a fresh device would.
- initializeTimeZoneSetting("", TIME_ZONE_CONFIDENCE_LOW);
- }
-
- void initializeClock(@ElapsedRealtimeLong long elapsedRealtimeMillis) {
- mElapsedRealtimeMillis = elapsedRealtimeMillis;
- }
-
- void initializeTimeZoneSetting(String zoneId, @TimeZoneConfidence int timeZoneConfidence) {
- mTimeZoneId.init(zoneId);
- mTimeZoneConfidence.init(timeZoneConfidence);
- }
-
- void incrementClock() {
- mElapsedRealtimeMillis++;
- }
-
- @Override
- public String getDeviceTimeZone() {
- return mTimeZoneId.getLatest();
- }
-
- @Override
- public int getDeviceTimeZoneConfidence() {
- return mTimeZoneConfidence.getLatest();
- }
-
- @Override
- public void setDeviceTimeZoneAndConfidence(
- String zoneId, @TimeZoneConfidence int confidence, String logInfo) {
- mTimeZoneId.set(zoneId);
- mTimeZoneConfidence.set(confidence);
- }
-
- void assertTimeZoneNotChanged() {
- mTimeZoneId.assertHasNotBeenSet();
- mTimeZoneConfidence.assertHasNotBeenSet();
- }
-
- void assertTimeZoneChangedTo(String timeZoneId, @TimeZoneConfidence int confidence) {
- mTimeZoneId.assertHasBeenSet();
- mTimeZoneId.assertChangeCount(1);
- mTimeZoneId.assertLatestEquals(timeZoneId);
-
- mTimeZoneConfidence.assertHasBeenSet();
- mTimeZoneConfidence.assertChangeCount(1);
- mTimeZoneConfidence.assertLatestEquals(confidence);
- }
-
- void commitAllChanges() {
- mTimeZoneId.commitLatest();
- mTimeZoneConfidence.commitLatest();
- }
-
- @Override
- @ElapsedRealtimeLong
- public long elapsedRealtimeMillis() {
- return mElapsedRealtimeMillis;
- }
-
- @Override
- public void addDebugLogEntry(String logMsg) {
- // No-op for tests
- }
-
- @Override
- public void dumpDebugLog(PrintWriter printWriter) {
- // No-op for tests
- }
-
- @Override
- public void runAsync(Runnable runnable) {
- mAsyncRunnables.add(runnable);
- }
-
- public void runAsyncRunnables() {
- for (Runnable runnable : mAsyncRunnables) {
- runnable.run();
- }
- mAsyncRunnables.clear();
- }
- }
-
private void assertStateChangeNotificationsSent(
TestStateChangeListener stateChangeListener, int expectedCount) {
// The fake environment needs to be told to run posted work.
@@ -2013,8 +1921,8 @@ public class TimeZoneDetectorStrategyImplTest {
return this;
}
- Script initializeClock(long elapsedRealtimeMillis) {
- mFakeEnvironment.initializeClock(elapsedRealtimeMillis);
+ Script initializeClock(long currentTimeMillis, long elapsedRealtimeMillis) {
+ mFakeEnvironment.initializeClock(currentTimeMillis, elapsedRealtimeMillis);
return this;
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index 4f5cdb73edd2..1df8e3deb84b 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -64,6 +64,8 @@ import android.testing.TestableContext;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IntArray;
+import android.util.StatsEvent;
+import android.util.StatsEventTestUtils;
import android.util.Xml;
import androidx.test.runner.AndroidJUnit4;
@@ -71,9 +73,17 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.CollectionUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
+import com.android.os.AtomsProto;
+import com.android.os.notification.NotificationBundlePreferences;
+import com.android.os.notification.NotificationExtensionAtoms;
+import com.android.os.notification.NotificationProtoEnums;
import com.android.server.UiServiceTestCase;
import com.android.server.notification.NotificationManagerService.NotificationAssistants;
+import com.google.protobuf.CodedInputStream;
+import com.google.protobuf.CodedOutputStream;
+import com.google.protobuf.ExtensionRegistryLite;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -120,6 +130,8 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
ComponentName mCn = new ComponentName("a", "b");
+ private ExtensionRegistryLite mRegistry;
+
// Helper function to hold mApproved lock, avoid GuardedBy lint errors
private boolean isUserSetServicesEmpty(NotificationAssistants assistant, int userId) {
@@ -204,6 +216,8 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
when(mNm.isNASMigrationDone(anyInt())).thenReturn(true);
when(mNm.canUseManagedServices(any(), anyInt(), any())).thenReturn(true);
+ mRegistry = ExtensionRegistryLite.newInstance();
+ NotificationExtensionAtoms.registerAllExtensions(mRegistry);
}
@Test
@@ -749,6 +763,28 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags({android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION,
+ android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
+ public void testGetPackagesWithKeyTypeAdjustmentSettings() throws Exception {
+ String pkg = "my.package";
+ String pkg2 = "my.package.2";
+ setDefaultAllowedAdjustmentKeyTypes(mAssistants);
+ assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(pkg, TYPE_PROMOTION)).isTrue();
+ assertThat(mAssistants.getPackagesWithKeyTypeAdjustmentSettings()).isEmpty();
+
+ mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(pkg, TYPE_PROMOTION, true);
+ assertThat(mAssistants.getPackagesWithKeyTypeAdjustmentSettings())
+ .containsExactly(pkg);
+ mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(pkg, TYPE_PROMOTION, false);
+ assertThat(mAssistants.getPackagesWithKeyTypeAdjustmentSettings())
+ .containsExactly(pkg);
+ mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(pkg2, TYPE_NEWS, true);
+ mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(pkg2, TYPE_PROMOTION, false);
+ assertThat(mAssistants.getPackagesWithKeyTypeAdjustmentSettings())
+ .containsExactly(pkg, pkg2);
+ }
+
+ @Test
@EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
public void testSetAssistantAdjustmentKeyTypeStateForPackage_usesGlobalDefault() {
String pkg = "my.package";
@@ -892,4 +928,88 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
assertThat(mAssistants.getAllowedAdjustmentKeyTypesForPackage(pkg)).asList()
.containsExactly(TYPE_NEWS, TYPE_PROMOTION, TYPE_SOCIAL_MEDIA);
}
+
+ @Test
+ @SuppressWarnings("GuardedBy")
+ @EnableFlags({android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION,
+ android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
+ public void testPullBundlePreferencesStats_fillsOutStatsEvent()
+ throws Exception {
+ // Create the current user and enable the package
+ int userId = ActivityManager.getCurrentUser();
+ mAssistants.loadDefaultsFromConfig(true);
+ mAssistants.setPackageOrComponentEnabled(mCn.flattenToString(), userId, true,
+ true, true);
+ ManagedServices.ManagedServiceInfo info =
+ mAssistants.new ManagedServiceInfo(null, mCn, userId, false, null, 35, 2345256);
+
+ // Ensure bundling is enabled
+ mAssistants.setAdjustmentTypeSupportedState(info, Adjustment.KEY_TYPE, true);
+ // Enable these specific bundle types
+ mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_PROMOTION, false);
+ mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, true);
+ mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_CONTENT_RECOMMENDATION, true);
+
+ // When pullBundlePreferencesStats is run with the given preferences
+ ArrayList<StatsEvent> events = new ArrayList<>();
+ mAssistants.pullBundlePreferencesStats(events);
+
+ // The StatsEvent is filled out with the expected NotificationBundlePreferences values.
+ assertThat(events.size()).isEqualTo(1);
+ AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(events.get(0));
+
+ // The returned atom does not have external extensions registered.
+ // So we serialize and then deserialize with extensions registered.
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ CodedOutputStream codedos = CodedOutputStream.newInstance(outputStream);
+ atom.writeTo(codedos);
+ codedos.flush();
+
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
+ CodedInputStream codedis = CodedInputStream.newInstance(inputStream);
+ atom = AtomsProto.Atom.parseFrom(codedis, mRegistry);
+ assertTrue(atom.hasExtension(NotificationExtensionAtoms.notificationBundlePreferences));
+ NotificationBundlePreferences p =
+ atom.getExtension(NotificationExtensionAtoms.notificationBundlePreferences);
+ assertThat(p.getBundlesAllowed()).isTrue();
+ assertThat(p.getAllowedBundleTypes(0).getNumber())
+ .isEqualTo(NotificationProtoEnums.TYPE_NEWS);
+ assertThat(p.getAllowedBundleTypes(1).getNumber())
+ .isEqualTo(NotificationProtoEnums.TYPE_CONTENT_RECOMMENDATION);
+
+ // Disable the top-level bundling setting
+ mAssistants.setAdjustmentTypeSupportedState(info, Adjustment.KEY_TYPE, false);
+ // Enable these specific bundle types
+ mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_PROMOTION, true);
+ mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, false);
+ mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_CONTENT_RECOMMENDATION, true);
+
+ ArrayList<StatsEvent> eventsDisabled = new ArrayList<>();
+ mAssistants.pullBundlePreferencesStats(eventsDisabled);
+
+ // The StatsEvent is filled out with the expected NotificationBundlePreferences values.
+ assertThat(eventsDisabled.size()).isEqualTo(1);
+ AtomsProto.Atom atomDisabled = StatsEventTestUtils.convertToAtom(eventsDisabled.get(0));
+
+ // The returned atom does not have external extensions registered.
+ // So we serialize and then deserialize with extensions registered.
+ outputStream = new ByteArrayOutputStream();
+ codedos = CodedOutputStream.newInstance(outputStream);
+ atomDisabled.writeTo(codedos);
+ codedos.flush();
+
+ inputStream = new ByteArrayInputStream(outputStream.toByteArray());
+ codedis = CodedInputStream.newInstance(inputStream);
+ atomDisabled = AtomsProto.Atom.parseFrom(codedis, mRegistry);
+ assertTrue(atomDisabled.hasExtension(NotificationExtensionAtoms
+ .notificationBundlePreferences));
+
+ NotificationBundlePreferences p2 =
+ atomDisabled.getExtension(NotificationExtensionAtoms.notificationBundlePreferences);
+ assertThat(p2.getBundlesAllowed()).isFalse();
+ assertThat(p2.getAllowedBundleTypes(0).getNumber())
+ .isEqualTo(NotificationProtoEnums.TYPE_PROMOTION);
+ assertThat(p2.getAllowedBundleTypes(1).getNumber())
+ .isEqualTo(NotificationProtoEnums.TYPE_CONTENT_RECOMMENDATION);
+ }
} \ No newline at end of file
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 e43b28bb9404..fdb6a6802b7e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -24,6 +24,7 @@ import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.NOT_
import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.SHOW_IMMEDIATELY;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.Flags.FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS;
+import static android.app.Flags.FLAG_REDACT_SENSITIVE_CONTENT_NOTIFICATIONS_ON_LOCKSCREEN;
import static android.app.Flags.FLAG_SORT_SECTION_BY_TIME;
import static android.app.Notification.EXTRA_ALLOW_DURING_SETUP;
import static android.app.Notification.EXTRA_PICTURE;
@@ -251,6 +252,9 @@ import android.graphics.drawable.Icon;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.session.MediaSession;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -475,6 +479,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Mock
private PowerManager mPowerManager;
@Mock
+ private ConnectivityManager mConnectivityManager;
+ @Mock
private LightsManager mLightsManager;
private final ArrayList<WakeLock> mAcquiredWakeLocks = new ArrayList<>();
private final TestPostNotificationTrackerFactory mPostNotificationTrackerFactory =
@@ -765,6 +771,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mActivityIntentImmutable = spy(PendingIntent.getActivity(mContext, 0,
new Intent().setPackage(mPkg), FLAG_IMMUTABLE));
+ when(mConnectivityManager.getActiveNetwork()).thenReturn(null);
+
initNMS();
}
@@ -798,7 +806,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mAppOpsManager, mUm, mHistoryManager, mStatsManager,
mAmi, mToastRateLimiter, mPermissionHelper, mock(UsageStatsManagerInternal.class),
mTelecomManager, mLogger, mTestFlagResolver, mPermissionManager,
- mPowerManager, mPostNotificationTrackerFactory);
+ mPowerManager, mConnectivityManager, mPostNotificationTrackerFactory);
mService.setAttentionHelper(mAttentionHelper);
mService.setLockPatternUtils(mock(LockPatternUtils.class));
@@ -14314,7 +14322,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.addNotification(pkgB);
mService.setIsVisibleToListenerReturnValue(true);
- NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(null);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
assertEquals(2, nru.getRankingMap().getOrderedKeys().length);
// when only user 0 entering the lockdown mode, its notification will be suppressed.
@@ -14324,7 +14333,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertTrue(mStrongAuthTracker.isInLockDownMode(0));
assertFalse(mStrongAuthTracker.isInLockDownMode(1));
- nru = mService.makeRankingUpdateLocked(null);
+ nru = mService.makeRankingUpdateLocked(info);
assertEquals(1, nru.getRankingMap().getOrderedKeys().length);
// User 0 exits lockdown mode. Its notification will be resumed.
@@ -14333,7 +14342,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertFalse(mStrongAuthTracker.isInLockDownMode(0));
assertFalse(mStrongAuthTracker.isInLockDownMode(1));
- nru = mService.makeRankingUpdateLocked(null);
+ nru = mService.makeRankingUpdateLocked(info);
assertEquals(2, nru.getRankingMap().getOrderedKeys().length);
}
@@ -14365,13 +14374,119 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertEquals(0, ranking2.getSmartReplies().size());
}
+ private NotificationRecord getSensitiveNotificationRecord() {
+ NotificationRecord record = new NotificationRecord(mContext,
+ generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
+ Bundle signals = new Bundle();
+ signals.putBoolean(Adjustment.KEY_SENSITIVE_CONTENT, true);
+ Adjustment adjustment = new Adjustment("a", record.getKey(), signals, "", 0);
+ record.addAdjustment(adjustment);
+ record.applyAdjustments();
+ return record;
+ }
+
+ @Test
+ public void testMakeRankingUpdate_clearsHasSensitiveContentIfConnectedToWifi() {
+ mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS,
+ FLAG_REDACT_SENSITIVE_CONTENT_NOTIFICATIONS_ON_LOCKSCREEN);
+ when(mConnectivityManager.getActiveNetwork()).thenReturn(mock(Network.class));
+ when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(
+ new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .build()
+ );
+ mService.updateWifiConnectionState();
+ when(mListeners.hasSensitiveContent(any())).thenReturn(true);
+ NotificationRecord pkgA = new NotificationRecord(mContext,
+ generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
+ mService.addNotification(pkgA);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ info.isSystemUi = true;
+ when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
+ when(info.isSameUser(anyInt())).thenReturn(true);
+ NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
+ NotificationListenerService.Ranking ranking =
+ nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey());
+ assertFalse(ranking.hasSensitiveContent());
+ }
+
+ @Test
+ public void testMakeRankingUpdate_doesntClearHasSensitiveContentIfNotConnectedToWifi() {
+ mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS,
+ FLAG_REDACT_SENSITIVE_CONTENT_NOTIFICATIONS_ON_LOCKSCREEN);
+ when(mConnectivityManager.getActiveNetwork()).thenReturn(mock(Network.class));
+ when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(
+ new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .build()
+ );
+ mService.updateWifiConnectionState();
+ when(mListeners.hasSensitiveContent(any())).thenReturn(true);
+ NotificationRecord record = getSensitiveNotificationRecord();
+ mService.addNotification(record);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ info.isSystemUi = true;
+ when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
+ when(info.isSameUser(anyInt())).thenReturn(true);
+ NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
+ NotificationListenerService.Ranking ranking =
+ nru.getRankingMap().getRawRankingObject(record.getSbn().getKey());
+ assertTrue(ranking.hasSensitiveContent());
+ }
+
+ @Test
+ public void testMakeRankingUpdate_doesntClearHasSensitiveContentIfNotSysUi() {
+ mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
+ mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_CONTENT_NOTIFICATIONS_ON_LOCKSCREEN);
+ when(mConnectivityManager.getActiveNetwork()).thenReturn(mock(Network.class));
+ when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(
+ new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .build()
+ );
+ mService.updateWifiConnectionState();
+ when(mListeners.hasSensitiveContent(any())).thenReturn(true);
+ NotificationRecord record = getSensitiveNotificationRecord();
+ mService.addNotification(record);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
+ when(info.isSameUser(anyInt())).thenReturn(true);
+ NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
+ NotificationListenerService.Ranking ranking =
+ nru.getRankingMap().getRawRankingObject(record.getSbn().getKey());
+ assertTrue(ranking.hasSensitiveContent());
+ }
+
+ @Test
+ public void testMakeRankingUpdate_doesntClearHasSensitiveContentIfFlagDisabled() {
+ mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
+ mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_CONTENT_NOTIFICATIONS_ON_LOCKSCREEN);
+ when(mConnectivityManager.getActiveNetwork()).thenReturn(mock(Network.class));
+ when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(
+ new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .build()
+ );
+ mService.updateWifiConnectionState();
+ when(mListeners.hasSensitiveContent(any())).thenReturn(true);
+ NotificationRecord record = getSensitiveNotificationRecord();
+ mService.addNotification(record);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ info.isSystemUi = true;
+ when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
+ when(info.isSameUser(anyInt())).thenReturn(true);
+ NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
+ NotificationListenerService.Ranking ranking =
+ nru.getRankingMap().getRawRankingObject(record.getSbn().getKey());
+ assertTrue(ranking.hasSensitiveContent());
+ }
+
@Test
public void testMakeRankingUpdate_doestntRedactIfFlagDisabled() {
mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
when(mListeners.isUidTrusted(anyInt())).thenReturn(false);
when(mListeners.hasSensitiveContent(any())).thenReturn(true);
- NotificationRecord pkgA = new NotificationRecord(mContext,
- generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
+ NotificationRecord pkgA = getSensitiveNotificationRecord();
addSmartActionsAndReplies(pkgA);
mService.addNotification(pkgA);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index f41805d40b0d..704b580a80b0 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -19,6 +19,7 @@ import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
import static android.app.Flags.FLAG_MODES_UI;
+import static android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI;
import static android.app.Notification.VISIBILITY_PRIVATE;
import static android.app.Notification.VISIBILITY_SECRET;
import static android.app.NotificationChannel.ALLOW_BUBBLE_ON;
@@ -115,6 +116,7 @@ import android.content.IContentProvider;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.content.res.Resources;
@@ -161,6 +163,7 @@ import com.android.modules.utils.TypedXmlSerializer;
import com.android.os.AtomsProto;
import com.android.os.AtomsProto.PackageNotificationChannelPreferences;
import com.android.os.AtomsProto.PackageNotificationPreferences;
+import com.android.os.notification.NotificationProtoEnums;
import com.android.server.UiServiceTestCase;
import com.android.server.notification.PermissionHelper.PackagePermission;
import com.android.server.uri.UriGrantsManagerInternal;
@@ -256,7 +259,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
public static List<FlagsParameterization> getParams() {
return FlagsParameterization.allCombinationsOf(
android.app.Flags.FLAG_API_RICH_ONGOING,
- FLAG_NOTIFICATION_CLASSIFICATION, FLAG_MODES_UI);
+ FLAG_NOTIFICATION_CLASSIFICATION, FLAG_NOTIFICATION_CLASSIFICATION_UI,
+ FLAG_MODES_UI);
}
public PreferencesHelperTest(FlagsParameterization flags) {
@@ -6135,6 +6139,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
+ @DisableFlags({FLAG_NOTIFICATION_CLASSIFICATION_UI})
public void testPullPackagePreferencesStats_postPermissionMigration()
throws InvalidProtocolBufferException {
// make sure there's at least one channel for each package we want to test
@@ -6155,6 +6160,11 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.canShowBadge(PKG_O, UID_O);
mHelper.canShowBadge(PKG_P, UID_P);
+ ArrayList<StatsEvent> events = new ArrayList<>();
+
+ mHelper.pullPackagePreferencesStats(events, appPermissions,
+ new ArrayMap<String, Set<Integer>>());
+
// expected output. format: uid -> importance, as only uid (and not package name)
// is in PackageNotificationPreferences
ArrayMap<Integer, Pair<Integer, Boolean>> expected = new ArrayMap<>();
@@ -6162,9 +6172,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
expected.put(UID_O, new Pair<>(IMPORTANCE_NONE, true)); // banned by permissions
expected.put(UID_P, new Pair<>(IMPORTANCE_UNSPECIFIED, false)); // default: unspecified
- ArrayList<StatsEvent> events = new ArrayList<>();
- mHelper.pullPackagePreferencesStats(events, appPermissions);
-
assertEquals("total number of packages", 3, events.size());
for (StatsEvent ev : events) {
AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
@@ -6180,6 +6187,74 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, FLAG_NOTIFICATION_CLASSIFICATION_UI})
+ public void testPullPackagePreferencesStats_createsExpectedStatsEvents()
+ throws InvalidProtocolBufferException {
+ // make sure there's at least one channel for each package we want to test
+ NotificationChannel channelA = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channelA, true, false,
+ UID_N_MR1, false);
+ NotificationChannel channelB = new NotificationChannel("b", "b", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channelB, true, false, UID_O, false);
+ NotificationChannel channelC = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_P, UID_P, channelC, true, false, UID_P, false);
+
+ // build a collection of app permissions that should be passed in and used
+ ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions = new ArrayMap<>();
+ pkgPermissions.put(new Pair<>(UID_N_MR1, PKG_N_MR1), new Pair<>(true, false));
+ pkgPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, true)); // in local prefs
+
+ // local preferences
+ mHelper.canShowBadge(PKG_O, UID_O);
+ mHelper.canShowBadge(PKG_P, UID_P);
+
+ // Sets bundles_allowed to true for these packages.
+ ArrayMap<String, Set<Integer>> packageSpecificAdjustmentKeyTypes = new ArrayMap<>();
+ Set<Integer> nMr1BundlesSet = new ArraySet<Integer>();
+ nMr1BundlesSet.add(TYPE_NEWS);
+ nMr1BundlesSet.add(TYPE_SOCIAL_MEDIA);
+ packageSpecificAdjustmentKeyTypes.put(PKG_N_MR1, nMr1BundlesSet);
+ Set<Integer> pBundlesSet = new ArraySet<Integer>();
+ packageSpecificAdjustmentKeyTypes.put(PKG_P, pBundlesSet);
+
+ ArrayList<StatsEvent> events = new ArrayList<>();
+
+ mHelper.pullPackagePreferencesStats(events, pkgPermissions,
+ packageSpecificAdjustmentKeyTypes);
+
+ assertEquals("total number of packages", 3, events.size());
+
+ AtomsProto.Atom atom0 = StatsEventTestUtils.convertToAtom(events.get(0));
+ assertTrue(atom0.hasPackageNotificationPreferences());
+ PackageNotificationPreferences p0 = atom0.getPackageNotificationPreferences();
+ assertThat(p0.getUid()).isEqualTo(UID_O);
+ assertThat(p0.getImportance()).isEqualTo(IMPORTANCE_NONE); // banned by permissions
+ assertThat(p0.getUserSetImportance()).isTrue();
+ assertThat(p0.getAllowedBundleTypesList()).hasSize(0);
+
+ AtomsProto.Atom atom1 = StatsEventTestUtils.convertToAtom(events.get(1));
+ assertTrue(atom1.hasPackageNotificationPreferences());
+ PackageNotificationPreferences p1 = atom1.getPackageNotificationPreferences();
+ assertThat(p1.getUid()).isEqualTo(UID_N_MR1);
+ assertThat(p1.getImportance()).isEqualTo(IMPORTANCE_DEFAULT);
+ assertThat(p1.getUserSetImportance()).isFalse();
+ assertThat(p1.getAllowedBundleTypesList()).hasSize(2);
+
+ assertThat(p1.getAllowedBundleTypes(0).getNumber())
+ .isEqualTo(NotificationProtoEnums.TYPE_SOCIAL_MEDIA);
+ assertThat(p1.getAllowedBundleTypes(1).getNumber())
+ .isEqualTo(NotificationProtoEnums.TYPE_NEWS);
+
+ AtomsProto.Atom atom2 = StatsEventTestUtils.convertToAtom(events.get(2));
+ assertTrue(atom2.hasPackageNotificationPreferences());
+ PackageNotificationPreferences p2 = atom2.getPackageNotificationPreferences();
+ assertThat(p2.getUid()).isEqualTo(UID_P);
+ assertThat(p2.getImportance()).isEqualTo(IMPORTANCE_UNSPECIFIED); // default: unspecified
+ assertThat(p2.getUserSetImportance()).isFalse();
+ assertThat(p2.getAllowedBundleTypesList()).hasSize(0);
+ }
+
+ @Test
public void testUnlockNotificationChannelImportance() {
NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW);
mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false);
@@ -6760,6 +6835,41 @@ public class PreferencesHelperTest extends UiServiceTestCase {
assertThat(mHelper.hasCacheBeenInvalidated()).isFalse();
}
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_NM_BINDER_PERF_CACHE_CHANNELS)
+ public void testGetNotificationChannels_createIfNeeded() {
+ // Test setup hasn't created any channels or read package preferences yet.
+ // If we ask for notification channels _without_ creating, we should get no result.
+ ParceledListSlice<NotificationChannel> channels = mHelper.getNotificationChannels(PKG_N_MR1,
+ UID_N_MR1, false, false, /* createPrefsIfNeeded= */ false);
+ assertThat(channels.getList().size()).isEqualTo(0);
+
+ // If we ask it to create package preferences, we expect the default channel to be created
+ // for N_MR1.
+ channels = mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false,
+ false, /* createPrefsIfNeeded= */ true);
+ assertThat(channels.getList().size()).isEqualTo(1);
+ assertThat(channels.getList().getFirst().getId()).isEqualTo(
+ NotificationChannel.DEFAULT_CHANNEL_ID);
+ }
+
+ @Test
+ @DisableFlags(android.app.Flags.FLAG_NM_BINDER_PERF_CACHE_CHANNELS)
+ public void testGetNotificationChannels_neverCreatesWhenFlagOff() {
+ ParceledListSlice<NotificationChannel> channels;
+ try {
+ channels = mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false,
+ false, /* createPrefsIfNeeded= */ true);
+ } catch (Exception e) {
+ // Slog.wtf kicks in, presumably
+ } finally {
+ channels = mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false,
+ false, /* createPrefsIfNeeded= */ false);
+ assertThat(channels.getList().size()).isEqualTo(0);
+ }
+
+ }
+
// Test version of PreferencesHelper whose only functional difference is that it does not
// interact with the real IpcDataCache, and instead tracks whether or not the cache has been
// invalidated since creation or the last reset.
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
index c1bb3e7408fc..82d87d40031a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -47,6 +47,7 @@ import android.companion.ICompanionDeviceManager;
import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
import android.os.Looper;
import android.os.PowerManager;
import android.os.UserHandle;
@@ -171,6 +172,7 @@ public class RoleObserverTest extends UiServiceTestCase {
mock(NotificationChannelLogger.class), new TestableFlagResolver(),
mock(PermissionManager.class),
mock(PowerManager.class),
+ mock(ConnectivityManager.class),
new NotificationManagerService.PostNotificationTrackerFactory() {});
} catch (SecurityException e) {
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 194d48a80a65..767c02bd268f 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -109,6 +109,7 @@ import com.android.internal.util.test.FakeSettingsProviderRule;
import com.android.server.LocalServices;
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
import com.android.server.pm.BackgroundUserSoundNotifier;
+import com.android.server.pm.UserManagerService;
import com.android.server.vibrator.VibrationSession.Status;
import org.junit.After;
@@ -896,8 +897,8 @@ public class VibratorManagerServiceTest {
}
@Test
- @EnableFlags(android.multiuser.Flags.FLAG_ADD_UI_FOR_SOUNDS_FROM_BACKGROUND_USERS)
public void vibrate_thenFgUserRequestsMute_getsCancelled() throws Throwable {
+ assumeTrue(UserManagerService.shouldShowNotificationForBackgroundUserSounds());
mockVibrators(1);
VibratorManagerService service = createSystemReadyService();
@@ -2758,8 +2759,8 @@ public class VibratorManagerServiceTest {
}
@Test
- @EnableFlags(android.multiuser.Flags.FLAG_ADD_UI_FOR_SOUNDS_FROM_BACKGROUND_USERS)
public void onExternalVibration_thenFgUserRequestsMute_doNotCancelVibration() throws Throwable {
+ assumeTrue(UserManagerService.shouldShowNotificationForBackgroundUserSounds());
mockVibrators(1);
mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
VibratorManagerService service = createSystemReadyService();
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
index 132f95bea360..b328fc2d5868 100644
--- a/services/tests/wmtests/Android.bp
+++ b/services/tests/wmtests/Android.bp
@@ -11,19 +11,46 @@ package {
default_applicable_licenses: ["frameworks_base_license"],
}
-// Include all test java files.
filegroup {
- name: "wmtests-sources",
+ name: "wmtests-support-sources",
srcs: [
- "src/**/*.java",
+ "src/com/android/server/wm/WindowManagerServiceTestSupport.kt",
],
+ path: "src",
+ visibility: ["//visibility:private"],
+}
+
+java_library {
+ name: "wmtests-support",
+ srcs: [":wmtests-support-sources"],
+ static_libs: [
+ "com.android.window.flags.window-aconfig-java",
+ "kotlin-stdlib",
+ "services.core",
+ ],
+ lint: {
+ test: true,
+ },
+ visibility: [
+ "//frameworks/base/services/tests/wmtests",
+ "//frameworks/opt/car/services/updatableServices/tests",
+ ],
+}
+
+// Include all test files, but exclude test support files.
+filegroup {
+ name: "wmtests-sources",
+ srcs: ["src/**/*.java"],
+ exclude_srcs: [":wmtests-support-sources"],
+ path: "src",
+ visibility: ["//visibility:private"],
}
java_genrule {
name: "wmtests.protologsrc",
srcs: [
- ":protolog-impl",
":protolog-groups",
+ ":protolog-impl",
":wmtests-sources",
],
tools: ["protologtool"],
@@ -52,33 +79,34 @@ android_test {
],
static_libs: [
- "frameworks-base-testutils",
- "services.core",
- "service-permission.stubs.system_server",
- "androidx.test.runner",
+ "CtsSurfaceValidatorLib",
+ "android.view.inputmethod.flags-aconfig-java",
"androidx.test.rules",
+ "androidx.test.runner",
+ "com.android.window.flags.window-aconfig-java",
+ "flag-junit",
"flickerlib",
+ "frameworks-base-testutils",
+ "hamcrest-library",
"junit-params",
+ "mockito-kotlin2",
"mockito-target-extended-minus-junit4",
+ "platform-compat-test-rules",
"platform-test-annotations",
+ "service-permission.stubs.system_server",
+ "service-sdksandbox.impl",
+ "services.core",
"servicestests-utils",
+ "testables",
"testng",
"truth",
- "testables",
- "hamcrest-library",
- "flag-junit",
- "platform-compat-test-rules",
- "CtsSurfaceValidatorLib",
- "service-sdksandbox.impl",
- "com.android.window.flags.window-aconfig-java",
- "android.view.inputmethod.flags-aconfig-java",
- "flag-junit",
+ "wmtests-support",
],
libs: [
"android.hardware.power-V1-java",
- "android.test.mock.stubs.system",
"android.test.base.stubs.system",
+ "android.test.mock.stubs.system",
"android.test.runner.stubs.system",
],
@@ -94,8 +122,8 @@ android_test {
platform_apis: true,
test_suites: [
- "device-tests",
"automotive-tests",
+ "device-tests",
],
certificate: "platform",
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 6fad82b26808..c88d5153ed66 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -692,7 +692,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// Asserts fixed orientation request is not ignored, and the orientation is changed.
assertNotEquals(activityCurOrientation, activity.getConfiguration().orientation);
- assertTrue(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(activity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
}
@@ -721,13 +721,13 @@ public class ActivityRecordTests extends WindowTestsBase {
assertEquals(ORIENTATION_PORTRAIT, activity.getConfiguration().orientation);
// Clear size compat.
- activity.mAppCompatController.getAppCompatSizeCompatModePolicy().clearSizeCompatMode();
+ activity.mAppCompatController.getSizeCompatModePolicy().clearSizeCompatMode();
activity.ensureActivityConfiguration();
mDisplayContent.sendNewConfiguration();
// Relaunching the app should still respect the orientation request.
assertEquals(ORIENTATION_PORTRAIT, activity.getConfiguration().orientation);
- assertTrue(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(activity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
}
@@ -742,7 +742,7 @@ public class ActivityRecordTests extends WindowTestsBase {
assertEquals(ORIENTATION_LANDSCAPE, activity.getTask().getConfiguration().orientation);
// The app should be letterboxed.
assertEquals(ORIENTATION_PORTRAIT, activity.getConfiguration().orientation);
- assertTrue(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(activity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
}
@@ -755,7 +755,7 @@ public class ActivityRecordTests extends WindowTestsBase {
assertEquals(ORIENTATION_LANDSCAPE, activity.getTask().getConfiguration().orientation);
// Activity is not letterboxed.
assertEquals(ORIENTATION_LANDSCAPE, activity.getConfiguration().orientation);
- assertFalse(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(activity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
}
@@ -770,7 +770,7 @@ public class ActivityRecordTests extends WindowTestsBase {
assertEquals(ORIENTATION_LANDSCAPE, activity.getTask().getConfiguration().orientation);
// Activity is not letterboxed.
assertEquals(ORIENTATION_LANDSCAPE, activity.getConfiguration().orientation);
- assertFalse(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(activity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
}
@@ -785,7 +785,7 @@ public class ActivityRecordTests extends WindowTestsBase {
assertEquals(ORIENTATION_LANDSCAPE, activity.getTask().getConfiguration().orientation);
// Activity is not letterboxed.
assertEquals(ORIENTATION_LANDSCAPE, activity.getConfiguration().orientation);
- assertFalse(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(activity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
}
@@ -3800,7 +3800,7 @@ public class ActivityRecordTests extends WindowTestsBase {
.setResizeMode(RESIZE_MODE_RESIZEABLE)
.setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
.build();
- activity.mAppCompatController.getAppCompatSizeCompatModePolicy().clearSizeCompatMode();
+ activity.mAppCompatController.getSizeCompatModePolicy().clearSizeCompatMode();
return activity;
}
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 00c9691835db..018ea58e7120 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
@@ -180,7 +180,7 @@ class AppCompatActivityRobot {
void setLetterboxedForFixedOrientationAndAspectRatio(boolean enabled) {
doReturn(enabled).when(mActivityStack.top().mAppCompatController
- .getAppCompatAspectRatioPolicy()).isLetterboxedForFixedOrientationAndAspectRatio();
+ .getAspectRatioPolicy()).isLetterboxedForFixedOrientationAndAspectRatio();
}
void enableFullscreenCameraCompatTreatmentForTopActivity(boolean enabled) {
@@ -213,7 +213,7 @@ class AppCompatActivityRobot {
void setShouldApplyUserMinAspectRatioOverride(boolean enabled) {
doReturn(enabled).when(mActivityStack.top().mAppCompatController
- .getAppCompatAspectRatioOverrides()).shouldApplyUserMinAspectRatioOverride();
+ .getAspectRatioOverrides()).shouldApplyUserMinAspectRatioOverride();
}
void setShouldCreateCompatDisplayInsets(boolean enabled) {
@@ -226,17 +226,17 @@ class AppCompatActivityRobot {
void setShouldApplyUserFullscreenOverride(boolean enabled) {
doReturn(enabled).when(mActivityStack.top().mAppCompatController
- .getAppCompatAspectRatioOverrides()).shouldApplyUserFullscreenOverride();
+ .getAspectRatioOverrides()).shouldApplyUserFullscreenOverride();
}
void setGetUserMinAspectRatioOverrideCode(@UserMinAspectRatio int overrideCode) {
doReturn(overrideCode).when(mActivityStack.top().mAppCompatController
- .getAppCompatAspectRatioOverrides()).getUserMinAspectRatioOverrideCode();
+ .getAspectRatioOverrides()).getUserMinAspectRatioOverrideCode();
}
void setGetUserMinAspectRatioOverrideValue(float overrideValue) {
doReturn(overrideValue).when(mActivityStack.top().mAppCompatController
- .getAppCompatAspectRatioOverrides()).getUserMinAspectRatio();
+ .getAspectRatioOverrides()).getUserMinAspectRatio();
}
void setIgnoreOrientationRequest(boolean enabled) {
@@ -525,7 +525,7 @@ class AppCompatActivityRobot {
activity.setRequestedOrientation(screenOrientation);
}
// Make sure to use the provided configuration to construct the size compat fields.
- activity.mAppCompatController.getAppCompatSizeCompatModePolicy().clearSizeCompatMode();
+ activity.mAppCompatController.getSizeCompatModePolicy().clearSizeCompatMode();
activity.ensureActivityConfiguration();
// Make sure the display configuration reflects the change of activity.
if (activity.mDisplayContent.updateOrientation()) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatAspectRatioOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatAspectRatioOverridesTest.java
index 14ef913e28db..f29cbc6b3360 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatAspectRatioOverridesTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatAspectRatioOverridesTest.java
@@ -413,7 +413,7 @@ public class AppCompatAspectRatioOverridesTest extends WindowTestsBase {
@Override
void onPostActivityCreation(@NonNull ActivityRecord activity) {
super.onPostActivityCreation(activity);
- spyOn(activity.mAppCompatController.getAppCompatAspectRatioOverrides());
+ spyOn(activity.mAppCompatController.getAspectRatioOverrides());
}
void checkShouldApplyUserFullscreenOverride(boolean expected) {
@@ -465,7 +465,7 @@ public class AppCompatAspectRatioOverridesTest extends WindowTestsBase {
}
private AppCompatAspectRatioOverrides getTopActivityAppCompatAspectRatioOverrides() {
- return activity().top().mAppCompatController.getAppCompatAspectRatioOverrides();
+ return activity().top().mAppCompatController.getAspectRatioOverrides();
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatFocusOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatFocusOverridesTest.java
index d8f845389727..5e49c8cdb917 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatFocusOverridesTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatFocusOverridesTest.java
@@ -188,7 +188,7 @@ public class AppCompatFocusOverridesTest extends WindowTestsBase {
}
void checkShouldSendFakeFocusOnTopActivity(boolean expected) {
- Assert.assertEquals(activity().top().mAppCompatController.getAppCompatFocusOverrides()
+ Assert.assertEquals(activity().top().mAppCompatController.getFocusOverrides()
.shouldSendFakeFocus(), expected);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java
index e046f7cc5845..b5ba111e4e72 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java
@@ -364,7 +364,7 @@ public class AppCompatLetterboxPolicyTest extends WindowTestsBase {
@NonNull
private AppCompatAspectRatioPolicy getAspectRatioPolicy() {
- return activity().top().mAppCompatController.getAppCompatAspectRatioPolicy();
+ return activity().top().mAppCompatController.getAspectRatioPolicy();
}
@NonNull
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationOverridesTest.java
index a0727a7af87b..9e46c09f3ff6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationOverridesTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationOverridesTest.java
@@ -275,7 +275,7 @@ public class AppCompatOrientationOverridesTest extends WindowTestsBase {
@Override
void onPostActivityCreation(@NonNull ActivityRecord activity) {
super.onPostActivityCreation(activity);
- spyOn(activity.mAppCompatController.getAppCompatAspectRatioPolicy());
+ spyOn(activity.mAppCompatController.getAspectRatioPolicy());
}
// Useful to reduce timeout during tests
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationPolicyTest.java
index 4faa71451a4d..f577c3a51e75 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationPolicyTest.java
@@ -555,8 +555,8 @@ public class AppCompatOrientationPolicyTest extends WindowTestsBase {
@Override
void onPostActivityCreation(@NonNull ActivityRecord activity) {
super.onPostActivityCreation(activity);
- spyOn(activity.mAppCompatController.getAppCompatAspectRatioOverrides());
- spyOn(activity.mAppCompatController.getAppCompatAspectRatioPolicy());
+ spyOn(activity.mAppCompatController.getAspectRatioOverrides());
+ spyOn(activity.mAppCompatController.getAspectRatioPolicy());
}
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatUtilsTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatUtilsTest.java
index a5b2cb39cfff..bfd533aa8f79 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatUtilsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatUtilsTest.java
@@ -252,7 +252,7 @@ public class AppCompatUtilsTest extends WindowTestsBase {
@Override
void onPostActivityCreation(@NonNull ActivityRecord activity) {
super.onPostActivityCreation(activity);
- spyOn(activity.mAppCompatController.getAppCompatAspectRatioPolicy());
+ spyOn(activity.mAppCompatController.getAspectRatioPolicy());
}
@Override
@@ -272,13 +272,13 @@ public class AppCompatUtilsTest extends WindowTestsBase {
void setIsLetterboxedForFixedOrientationAndAspectRatio(
boolean forFixedOrientationAndAspectRatio) {
- when(activity().top().mAppCompatController.getAppCompatAspectRatioPolicy()
+ when(activity().top().mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio())
.thenReturn(forFixedOrientationAndAspectRatio);
}
void setIsLetterboxedForAspectRatioOnly(boolean forAspectRatio) {
- when(activity().top().mAppCompatController.getAppCompatAspectRatioPolicy()
+ when(activity().top().mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForAspectRatioOnly()).thenReturn(forAspectRatio);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
index b6f442460ec8..576d17af2e79 100644
--- a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
@@ -606,7 +606,7 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
.setOnTop(true)
.setTask(task)
.build();
- mActivity.mAppCompatController.getAppCompatSizeCompatModePolicy().clearSizeCompatMode();
+ mActivity.mAppCompatController.getSizeCompatModePolicy().clearSizeCompatMode();
spyOn(mActivity.mAppCompatController.getAppCompatCameraOverrides());
spyOn(mActivity.info);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopAppCompatAspectRatioPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DesktopAppCompatAspectRatioPolicyTests.java
index f4e1d4967ff5..fa7dcc8ebbc7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DesktopAppCompatAspectRatioPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DesktopAppCompatAspectRatioPolicyTests.java
@@ -407,8 +407,8 @@ public class DesktopAppCompatAspectRatioPolicyTests extends WindowTestsBase {
@Override
void onPostActivityCreation(@NonNull ActivityRecord activity) {
super.onPostActivityCreation(activity);
- spyOn(activity.mAppCompatController.getAppCompatAspectRatioOverrides());
- spyOn(activity.mAppCompatController.getDesktopAppCompatAspectRatioPolicy());
+ spyOn(activity.mAppCompatController.getAspectRatioOverrides());
+ spyOn(activity.mAppCompatController.getDesktopAspectRatioPolicy());
}
void setDesiredAspectRatio(float aspectRatio) {
@@ -417,7 +417,7 @@ public class DesktopAppCompatAspectRatioPolicyTests extends WindowTestsBase {
}
DesktopAppCompatAspectRatioPolicy getDesktopAppCompatAspectRatioPolicy() {
- return getTopActivity().mAppCompatController.getDesktopAppCompatAspectRatioPolicy();
+ return getTopActivity().mAppCompatController.getDesktopAspectRatioPolicy();
}
float calculateAspectRatio() {
@@ -430,7 +430,7 @@ public class DesktopAppCompatAspectRatioPolicyTests extends WindowTestsBase {
}
float getSplitScreenAspectRatio() {
- return getTopActivity().mAppCompatController.getAppCompatAspectRatioOverrides()
+ return getTopActivity().mAppCompatController.getAspectRatioOverrides()
.getSplitScreenAspectRatio();
}
@@ -442,7 +442,7 @@ public class DesktopAppCompatAspectRatioPolicyTests extends WindowTestsBase {
void checkHasMinAspectRatioOverride(boolean expected) {
assertEquals(expected, this.activity().top().mAppCompatController
- .getDesktopAppCompatAspectRatioPolicy().hasMinAspectRatioOverride(
+ .getDesktopAspectRatioPolicy().hasMinAspectRatioOverride(
this.activity().top().getTask()));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
index 6d508eabcd52..cdb51fc1c645 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
@@ -265,9 +265,9 @@ public class DesktopModeLaunchParamsModifierTests extends
final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_LANDSCAPE,
task, /* ignoreOrientationRequest */ true);
- spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides());
+ spyOn(mActivity.mAppCompatController.getAspectRatioOverrides());
doReturn(true).when(
- mActivity.mAppCompatController.getAppCompatAspectRatioOverrides())
+ mActivity.mAppCompatController.getAspectRatioOverrides())
.isUserFullscreenOverrideEnabled();
final int desiredWidth =
@@ -293,9 +293,9 @@ public class DesktopModeLaunchParamsModifierTests extends
final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_LANDSCAPE,
task, /* ignoreOrientationRequest */ true);
- spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides());
+ spyOn(mActivity.mAppCompatController.getAspectRatioOverrides());
doReturn(true).when(
- mActivity.mAppCompatController.getAppCompatAspectRatioOverrides())
+ mActivity.mAppCompatController.getAspectRatioOverrides())
.isSystemOverrideToFullscreenEnabled();
final int desiredWidth =
@@ -320,9 +320,9 @@ public class DesktopModeLaunchParamsModifierTests extends
final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
task, /* ignoreOrientationRequest */ true);
- spyOn(activity.mAppCompatController.getDesktopAppCompatAspectRatioPolicy());
+ spyOn(activity.mAppCompatController.getDesktopAspectRatioPolicy());
doReturn(LETTERBOX_ASPECT_RATIO).when(activity.mAppCompatController
- .getDesktopAppCompatAspectRatioPolicy()).calculateAspectRatio(any());
+ .getDesktopAspectRatioPolicy()).calculateAspectRatio(any());
final int desiredWidth =
(int) ((LANDSCAPE_DISPLAY_BOUNDS.height() / LETTERBOX_ASPECT_RATIO) + 0.5f);
@@ -424,7 +424,7 @@ public class DesktopModeLaunchParamsModifierTests extends
(int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
final int desiredWidth =
(int) (desiredHeight / activity.mAppCompatController
- .getAppCompatAspectRatioOverrides().getSplitScreenAspectRatio());
+ .getAspectRatioOverrides().getSplitScreenAspectRatio());
assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
.setActivity(activity).calculate());
@@ -525,7 +525,7 @@ public class DesktopModeLaunchParamsModifierTests extends
final int desiredWidth =
(int) (PORTRAIT_DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
final int desiredHeight = (int) (desiredWidth * activity.mAppCompatController
- .getAppCompatAspectRatioOverrides().getSplitScreenAspectRatio());
+ .getAspectRatioOverrides().getSplitScreenAspectRatio());
assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(task)
.setActivity(activity).calculate());
@@ -616,7 +616,7 @@ public class DesktopModeLaunchParamsModifierTests extends
final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_UNSPECIFIED,
task, /* ignoreOrientationRequest */ true);
final float userAspectRatioOverrideValueSplitScreen = activity.mAppCompatController
- .getAppCompatAspectRatioOverrides().getSplitScreenAspectRatio();
+ .getAspectRatioOverrides().getSplitScreenAspectRatio();
applyUserMinAspectRatioOverride(activity, USER_MIN_ASPECT_RATIO_SPLIT_SCREEN,
userAspectRatioOverrideValueSplitScreen);
@@ -641,7 +641,7 @@ public class DesktopModeLaunchParamsModifierTests extends
final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_UNSPECIFIED,
task, /* ignoreOrientationRequest */ true);
final float userAspectRatioOverrideValueDisplaySize = activity.mAppCompatController
- .getAppCompatAspectRatioOverrides().getDisplaySizeMinAspectRatio();
+ .getAspectRatioOverrides().getDisplaySizeMinAspectRatio();
applyUserMinAspectRatioOverride(activity, USER_MIN_ASPECT_RATIO_DISPLAY_SIZE,
userAspectRatioOverrideValueDisplaySize);
@@ -738,7 +738,7 @@ public class DesktopModeLaunchParamsModifierTests extends
final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_UNSPECIFIED,
task, /* ignoreOrientationRequest */ true);
final float userAspectRatioOverrideValueSplitScreen = activity.mAppCompatController
- .getAppCompatAspectRatioOverrides().getSplitScreenAspectRatio();
+ .getAspectRatioOverrides().getSplitScreenAspectRatio();
applyUserMinAspectRatioOverride(activity, USER_MIN_ASPECT_RATIO_SPLIT_SCREEN,
userAspectRatioOverrideValueSplitScreen);
@@ -763,7 +763,7 @@ public class DesktopModeLaunchParamsModifierTests extends
final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_UNSPECIFIED,
task, /* ignoreOrientationRequest */ true);
final float userAspectRatioOverrideValueDisplaySize = activity.mAppCompatController
- .getAppCompatAspectRatioOverrides().getDisplaySizeMinAspectRatio();
+ .getAspectRatioOverrides().getDisplaySizeMinAspectRatio();
applyUserMinAspectRatioOverride(activity, USER_MIN_ASPECT_RATIO_DISPLAY_SIZE,
userAspectRatioOverrideValueDisplaySize);
@@ -812,9 +812,9 @@ public class DesktopModeLaunchParamsModifierTests extends
final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
task, /* ignoreOrientationRequest */ true);
- spyOn(activity.mAppCompatController.getDesktopAppCompatAspectRatioPolicy());
+ spyOn(activity.mAppCompatController.getDesktopAspectRatioPolicy());
doReturn(LETTERBOX_ASPECT_RATIO).when(activity.mAppCompatController
- .getDesktopAppCompatAspectRatioPolicy()).calculateAspectRatio(any());
+ .getDesktopAspectRatioPolicy()).calculateAspectRatio(any());
final int desiredHeight =
(int) (LANDSCAPE_DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
@@ -884,9 +884,9 @@ public class DesktopModeLaunchParamsModifierTests extends
final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
task, /* ignoreOrientationRequest */ true);
- spyOn(activity.mAppCompatController.getAppCompatAspectRatioOverrides());
+ spyOn(activity.mAppCompatController.getAspectRatioOverrides());
doReturn(true).when(
- activity.mAppCompatController.getAppCompatAspectRatioOverrides())
+ activity.mAppCompatController.getAspectRatioOverrides())
.isUserFullscreenOverrideEnabled();
final int desiredWidth =
@@ -912,9 +912,9 @@ public class DesktopModeLaunchParamsModifierTests extends
final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_PORTRAIT,
task, /* ignoreOrientationRequest */ true);
- spyOn(activity.mAppCompatController.getAppCompatAspectRatioOverrides());
+ spyOn(activity.mAppCompatController.getAspectRatioOverrides());
doReturn(true).when(
- activity.mAppCompatController.getAppCompatAspectRatioOverrides())
+ activity.mAppCompatController.getAspectRatioOverrides())
.isSystemOverrideToFullscreenEnabled();
final int desiredWidth =
@@ -939,9 +939,9 @@ public class DesktopModeLaunchParamsModifierTests extends
final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_LANDSCAPE,
task, /* ignoreOrientationRequest */ true);
- spyOn(activity.mAppCompatController.getDesktopAppCompatAspectRatioPolicy());
+ spyOn(activity.mAppCompatController.getDesktopAspectRatioPolicy());
doReturn(LETTERBOX_ASPECT_RATIO).when(activity.mAppCompatController
- .getDesktopAppCompatAspectRatioPolicy()).calculateAspectRatio(any());
+ .getDesktopAspectRatioPolicy()).calculateAspectRatio(any());
final int desiredWidth = PORTRAIT_DISPLAY_BOUNDS.width()
- (DESKTOP_MODE_LANDSCAPE_APP_PADDING * 2);
@@ -989,9 +989,9 @@ public class DesktopModeLaunchParamsModifierTests extends
final ActivityRecord activity = createActivity(display, SCREEN_ORIENTATION_LANDSCAPE,
task, /* ignoreOrientationRequest */ true);
- spyOn(activity.mAppCompatController.getDesktopAppCompatAspectRatioPolicy());
+ spyOn(activity.mAppCompatController.getDesktopAspectRatioPolicy());
doReturn(LETTERBOX_ASPECT_RATIO).when(activity.mAppCompatController
- .getDesktopAppCompatAspectRatioPolicy()).calculateAspectRatio(any());
+ .getDesktopAspectRatioPolicy()).calculateAspectRatio(any());
final int desiredWidth = PORTRAIT_DISPLAY_BOUNDS.width()
- (DESKTOP_MODE_LANDSCAPE_APP_PADDING * 2);
@@ -1294,7 +1294,7 @@ public class DesktopModeLaunchParamsModifierTests extends
private void setDesiredAspectRatio(ActivityRecord activity, float aspectRatio) {
final DesktopAppCompatAspectRatioPolicy desktopAppCompatAspectRatioPolicy =
- activity.mAppCompatController.getDesktopAppCompatAspectRatioPolicy();
+ activity.mAppCompatController.getDesktopAspectRatioPolicy();
spyOn(desktopAppCompatAspectRatioPolicy);
doReturn(aspectRatio).when(desktopAppCompatAspectRatioPolicy)
.getDesiredAspectRatio(any());
@@ -1304,7 +1304,7 @@ public class DesktopModeLaunchParamsModifierTests extends
float overrideValue) {
// Set desired aspect ratio to be below minimum so override can take effect.
final DesktopAppCompatAspectRatioPolicy desktopAppCompatAspectRatioPolicy =
- activity.mAppCompatController.getDesktopAppCompatAspectRatioPolicy();
+ activity.mAppCompatController.getDesktopAspectRatioPolicy();
spyOn(desktopAppCompatAspectRatioPolicy);
doReturn(1f).when(desktopAppCompatAspectRatioPolicy)
.getDesiredAspectRatio(any());
@@ -1318,7 +1318,7 @@ public class DesktopModeLaunchParamsModifierTests extends
// Simulate user min aspect ratio override being set.
final AppCompatAspectRatioOverrides appCompatAspectRatioOverrides =
- activity.mAppCompatController.getAppCompatAspectRatioOverrides();
+ activity.mAppCompatController.getAspectRatioOverrides();
spyOn(appCompatAspectRatioOverrides);
doReturn(overrideValue).when(appCompatAspectRatioOverrides).getUserMinAspectRatio();
doReturn(overrideCode).when(appCompatAspectRatioOverrides)
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 dfd10ec86a20..d76a907ba010 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1583,42 +1583,6 @@ public class DisplayContentTests extends WindowTestsBase {
is(Configuration.ORIENTATION_PORTRAIT));
}
- @Test
- public void testHybridRotationAnimation() {
- final DisplayContent displayContent = mDefaultDisplay;
- final WindowState statusBar = newWindowBuilder("statusBar", TYPE_STATUS_BAR).build();
- final WindowState navBar = newWindowBuilder("navBar", TYPE_NAVIGATION_BAR).build();
- final WindowState app = newWindowBuilder("app", TYPE_BASE_APPLICATION).build();
- final WindowState[] windows = { statusBar, navBar, app };
- makeWindowVisible(windows);
- final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
- displayPolicy.addWindowLw(statusBar, statusBar.mAttrs);
- displayPolicy.addWindowLw(navBar, navBar.mAttrs);
- final ScreenRotationAnimation rotationAnim = new ScreenRotationAnimation(displayContent,
- displayContent.getRotation());
- spyOn(rotationAnim);
- // Assume that the display rotation is changed so it is frozen in preparation for animation.
- doReturn(true).when(rotationAnim).hasScreenshot();
- displayContent.getDisplayRotation().setRotation((displayContent.getRotation() + 1) % 4);
- displayContent.setRotationAnimation(rotationAnim);
- // The fade rotation animation also starts to hide some non-app windows.
- assertNotNull(displayContent.getAsyncRotationController());
- assertTrue(statusBar.isAnimating(PARENTS, ANIMATION_TYPE_TOKEN_TRANSFORM));
-
- for (WindowState w : windows) {
- w.setOrientationChanging(true);
- }
- // The display only waits for the app window to unfreeze.
- assertFalse(displayContent.shouldSyncRotationChange(statusBar));
- assertFalse(displayContent.shouldSyncRotationChange(navBar));
- assertTrue(displayContent.shouldSyncRotationChange(app));
- // If all windows animated by fade rotation animation have done the orientation change,
- // the animation controller should be cleared.
- statusBar.setOrientationChanging(false);
- navBar.setOrientationChanging(false);
- assertNull(displayContent.getAsyncRotationController());
- }
-
@SetupWindows(addWindows = { W_ACTIVITY, W_WALLPAPER, W_STATUS_BAR, W_NAVIGATION_BAR,
W_INPUT_METHOD, W_NOTIFICATION_SHADE })
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index dc16de1aab5e..f509706d1692 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -118,7 +118,8 @@ public class DragDropControllerTests extends WindowTestsBase {
static class TestDragDropController extends DragDropController {
private Runnable mCloseCallback;
- boolean mDeferDragStateClosed;
+ private boolean mDeferDragStateClosed;
+ private DragState mPendingCloseDragState;
boolean mIsAccessibilityDrag;
TestDragDropController(WindowManagerService service, Looper looper) {
@@ -135,9 +136,26 @@ public class DragDropControllerTests extends WindowTestsBase {
}
}
+ /**
+ * Caller of this is expected to also call
+ * {@link TestDragDropController#continueDragStateClose} to properly close and clean up
+ * DragState.
+ */
+ void deferDragStateClose() {
+ mDeferDragStateClosed = true;
+ }
+
+ void continueDragStateClose() {
+ mDeferDragStateClosed = false;
+ if (mPendingCloseDragState != null) {
+ onDragStateClosedLocked(mPendingCloseDragState);
+ }
+ }
+
@Override
void onDragStateClosedLocked(DragState dragState) {
if (mDeferDragStateClosed) {
+ mPendingCloseDragState = dragState;
return;
}
super.onDragStateClosedLocked(dragState);
@@ -264,7 +282,7 @@ public class DragDropControllerTests extends WindowTestsBase {
// Verify after consuming that the drag surface is relinquished
try {
- mTarget.mDeferDragStateClosed = true;
+ mTarget.deferDragStateClose();
mTarget.reportDropWindow(mWindow.mInputChannelToken, 0, 0);
// Verify the drop event includes the drag surface
mTarget.handleMotionEvent(false, mWindow.getDisplayId(), 0, 0);
@@ -273,9 +291,9 @@ public class DragDropControllerTests extends WindowTestsBase {
mTarget.reportDropResult(iwindow, true);
} finally {
- mTarget.mDeferDragStateClosed = false;
+ assertTrue(mTarget.dragSurfaceRelinquishedToDropTarget());
+ mTarget.continueDragStateClose();
}
- assertTrue(mTarget.dragSurfaceRelinquishedToDropTarget());
});
}
@@ -350,7 +368,7 @@ public class DragDropControllerTests extends WindowTestsBase {
| View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG));
try {
- mTarget.mDeferDragStateClosed = true;
+ mTarget.deferDragStateClose();
mTarget.reportDropWindow(mWindow.mInputChannelToken, 0, 0);
// Verify the drop event does not have the drag flags
mTarget.handleMotionEvent(false, mWindow.getDisplayId(), 0, 0);
@@ -360,7 +378,7 @@ public class DragDropControllerTests extends WindowTestsBase {
mTarget.reportDropResult(iwindow, true);
} finally {
- mTarget.mDeferDragStateClosed = false;
+ mTarget.continueDragStateClose();
}
});
}
@@ -401,7 +419,7 @@ public class DragDropControllerTests extends WindowTestsBase {
assertEquals(-startOffsetPx, dragEvent2.getY(), 0.0 /* delta */);
try {
- mTarget.mDeferDragStateClosed = true;
+ mTarget.deferDragStateClose();
// x, y is window-local coordinate.
mTarget.reportDropWindow(window2.mInputChannelToken, dropCoordsPx,
dropCoordsPx);
@@ -424,7 +442,7 @@ public class DragDropControllerTests extends WindowTestsBase {
assertEquals(ACTION_DRAG_ENDED, last(dragEvents2).getAction());
assertEquals(window2.getDisplayId(), last(dragEvents2).getDisplayId());
} finally {
- mTarget.mDeferDragStateClosed = false;
+ mTarget.continueDragStateClose();
}
});
}
@@ -463,7 +481,7 @@ public class DragDropControllerTests extends WindowTestsBase {
assertEquals(-window2.getBounds().top - 1, dragEvent2.getY(), 0.0 /* delta */);
try {
- mTarget.mDeferDragStateClosed = true;
+ mTarget.deferDragStateClose();
mTarget.handleMotionEvent(true, testDisplay.getDisplayId(), dropCoordsPx,
dropCoordsPx);
// x, y is window-local coordinate.
@@ -488,7 +506,7 @@ public class DragDropControllerTests extends WindowTestsBase {
assertEquals(ACTION_DRAG_ENDED, last(dragEvents2).getAction());
assertEquals(testDisplay.getDisplayId(), last(dragEvents2).getDisplayId());
} finally {
- mTarget.mDeferDragStateClosed = false;
+ mTarget.continueDragStateClose();
}
});
}
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 347d1bc1becc..a7e8ce915f07 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
@@ -216,7 +216,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
final Rect activityBounds = new Rect(mFirstActivity.getBounds());
// DAG is portrait (860x1200), so Task and Activity fill DAG.
- assertThat(mFirstActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertThat(mFirstActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
assertThat(taskBounds).isEqualTo(dagBounds);
@@ -241,7 +241,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
new Rect(mFirstActivity.getConfiguration().windowConfiguration.getBounds());
// DAG is landscape (1200x860), no fixed orientation letterbox
- assertThat(mFirstActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertThat(mFirstActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mFirstActivity.inSizeCompatMode()).isTrue();
assertThat(newDagBounds.width()).isEqualTo(dagBounds.height());
@@ -266,12 +266,12 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_NOSENSOR);
- assertThat(mFirstActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertThat(mFirstActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
rotateDisplay(mDisplay, ROTATION_90);
- assertThat(mFirstActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertThat(mFirstActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
}
@@ -289,7 +289,7 @@ 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.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertThat(mFirstActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio()).isTrue();
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
assertThat(taskBounds).isEqualTo(dagBounds);
@@ -307,7 +307,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_NOSENSOR);
- assertThat(mFirstActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertThat(mFirstActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
}
@@ -318,7 +318,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_LOCKED);
- assertThat(mFirstActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertThat(mFirstActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
}
@@ -338,7 +338,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
final Rect newActivityBounds = new Rect(mFirstActivity.getBounds());
// DAG is landscape (1200x860), no fixed orientation letterbox
- assertThat(mFirstActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertThat(mFirstActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mFirstActivity.inSizeCompatMode()).isTrue();
assertThat(newDagBounds.width()).isEqualTo(dagBounds.height());
@@ -364,7 +364,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
rotateDisplay(mDisplay, ROTATION_90);
- assertThat(mFirstActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertThat(mFirstActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
}
@@ -527,7 +527,7 @@ 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.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertThat(mFirstActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
@@ -540,14 +540,14 @@ 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.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertThat(mSecondActivity.mAppCompatController.getAspectRatioPolicy()
.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.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertThat(mFirstActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio()).isTrue();
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 25b9f4b8035b..8a7e7434e604 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -70,8 +70,6 @@ import android.os.Bundle;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserManager;
-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 android.util.ArraySet;
@@ -82,11 +80,9 @@ import android.window.TaskSnapshot;
import androidx.test.filters.MediumTest;
-import com.android.launcher3.Flags;
import com.android.server.wm.RecentTasks.Callbacks;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -717,18 +713,7 @@ public class RecentTasksTest extends WindowTestsBase {
}
@Test
- @DisableFlags(Flags.FLAG_ENABLE_USE_TOP_VISIBLE_ACTIVITY_FOR_EXCLUDE_FROM_RECENT_TASK)
- public void testVisibleTasks_excludedFromRecents() {
- testVisibleTasks_excludedFromRecents_internal();
- }
-
- @Test
- @EnableFlags(Flags.FLAG_ENABLE_USE_TOP_VISIBLE_ACTIVITY_FOR_EXCLUDE_FROM_RECENT_TASK)
public void testVisibleTasks_excludedFromRecents_withRefactorFlag() {
- testVisibleTasks_excludedFromRecents_internal();
- }
-
- private void testVisibleTasks_excludedFromRecents_internal() {
mRecentTasks.setParameters(-1 /* min */, 4 /* max */, -1 /* ms */);
Task invisibleExcludedTask = createTaskBuilder(".ExcludedTask1")
@@ -766,19 +751,7 @@ public class RecentTasksTest extends WindowTestsBase {
}
@Test
- @Ignore("b/342627272")
- @DisableFlags(Flags.FLAG_ENABLE_USE_TOP_VISIBLE_ACTIVITY_FOR_EXCLUDE_FROM_RECENT_TASK)
- public void testVisibleTasks_excludedFromRecents_visibleTaskNotFirstTask() {
- testVisibleTasks_excludedFromRecents_visibleTaskNotFirstTask_internal();
- }
-
- @Test
- @EnableFlags(Flags.FLAG_ENABLE_USE_TOP_VISIBLE_ACTIVITY_FOR_EXCLUDE_FROM_RECENT_TASK)
public void testVisibleTasks_excludedFromRecents_visibleTaskNotFirstTask_withRefactorFlag() {
- testVisibleTasks_excludedFromRecents_visibleTaskNotFirstTask_internal();
- }
-
- private void testVisibleTasks_excludedFromRecents_visibleTaskNotFirstTask_internal() {
mRecentTasks.setParameters(-1 /* min */, 4 /* max */, -1 /* ms */);
Task invisibleExcludedTask = createTaskBuilder(".ExcludedTask1")
@@ -816,18 +789,7 @@ public class RecentTasksTest extends WindowTestsBase {
}
@Test
- @DisableFlags(Flags.FLAG_ENABLE_USE_TOP_VISIBLE_ACTIVITY_FOR_EXCLUDE_FROM_RECENT_TASK)
- public void testVisibleTasks_excludedFromRecents_firstTaskNotVisible() {
- testVisibleTasks_excludedFromRecents_firstTaskNotVisible_internal();
- }
-
- @Test
- @EnableFlags(Flags.FLAG_ENABLE_USE_TOP_VISIBLE_ACTIVITY_FOR_EXCLUDE_FROM_RECENT_TASK)
public void testVisibleTasks_excludedFromRecents_firstTaskNotVisible_withRefactorFlag() {
- testVisibleTasks_excludedFromRecents_firstTaskNotVisible_internal();
- }
-
- private void testVisibleTasks_excludedFromRecents_firstTaskNotVisible_internal() {
// Create some set of tasks, some of which are visible and some are not
Task homeTask = createTaskBuilder("com.android.pkg1", ".HomeTask")
.setParentTask(mTaskContainer.getRootHomeTask())
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 7e62b89d35bb..fc4f54a431d6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -535,7 +535,7 @@ public class RootWindowContainerTests extends WindowTestsBase {
final Rect bounds = new Rect(task.getBounds());
bounds.scale(0.5f);
task.setBounds(bounds);
- assertFalse(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(activity.mAppCompatController.getAspectRatioPolicy()
.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 07ee09a350d9..a84b374f9487 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -673,7 +673,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertFalse(mActivity.mDisplayContent.shouldImeAttachedToApp());
// Recompute the natural configuration without resolving size compat configuration.
- mActivity.mAppCompatController.getAppCompatSizeCompatModePolicy().clearSizeCompatMode();
+ mActivity.mAppCompatController.getSizeCompatModePolicy().clearSizeCompatMode();
mActivity.onConfigurationChanged(mTask.getConfiguration());
// It should keep non-attachable because the resolved bounds will be computed according to
// the aspect ratio that won't match its parent bounds.
@@ -765,7 +765,7 @@ public class SizeCompatTests extends WindowTestsBase {
/ originalBounds.width()));
// Recompute the natural configuration in the new display.
- mActivity.mAppCompatController.getAppCompatSizeCompatModePolicy().clearSizeCompatMode();
+ mActivity.mAppCompatController.getSizeCompatModePolicy().clearSizeCompatMode();
mActivity.ensureActivityConfiguration();
// Because the display cannot rotate, the portrait activity will fit the short side of
// display with keeping portrait bounds [200, 0 - 700, 1000] in center.
@@ -1143,11 +1143,11 @@ public class SizeCompatTests extends WindowTestsBase {
// Simulate the user selecting the fullscreen user aspect ratio override
spyOn(activity.mWmService.mAppCompatConfiguration);
- spyOn(activity.mAppCompatController.getAppCompatAspectRatioOverrides());
+ spyOn(activity.mAppCompatController.getAspectRatioOverrides());
doReturn(true).when(activity.mWmService.mAppCompatConfiguration)
.isUserAppAspectRatioFullscreenEnabled();
doReturn(USER_MIN_ASPECT_RATIO_FULLSCREEN)
- .when(activity.mAppCompatController.getAppCompatAspectRatioOverrides())
+ .when(activity.mAppCompatController.getAspectRatioOverrides())
.getUserMinAspectRatioOverrideCode();
assertFalse(activity.shouldCreateAppCompatDisplayInsets());
}
@@ -1165,9 +1165,9 @@ public class SizeCompatTests extends WindowTestsBase {
RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
// Simulate the user selecting the fullscreen user aspect ratio override
- spyOn(activity.mAppCompatController.getAppCompatAspectRatioOverrides());
+ spyOn(activity.mAppCompatController.getAspectRatioOverrides());
doReturn(true).when(
- activity.mAppCompatController.getAppCompatAspectRatioOverrides())
+ activity.mAppCompatController.getAspectRatioOverrides())
.isSystemOverrideToFullscreenEnabled();
assertFalse(activity.shouldCreateAppCompatDisplayInsets());
}
@@ -1187,7 +1187,7 @@ 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.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(activity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertThat(activity.getConfiguration().windowConfiguration.getMaxBounds())
.isEqualTo(activity.getDisplayArea().getBounds());
@@ -1229,7 +1229,7 @@ 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.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(activity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertThat(activity.getConfiguration().windowConfiguration.getMaxBounds())
.isEqualTo(activity.getDisplayArea().getBounds());
@@ -1253,7 +1253,7 @@ 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.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(activity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertThat(activity.getConfiguration().windowConfiguration.getMaxBounds())
.isEqualTo(activity.getDisplayArea().getBounds());
@@ -1507,7 +1507,7 @@ public class SizeCompatTests extends WindowTestsBase {
// After changing the orientation to portrait the override should be applied.
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- activity.mAppCompatController.getAppCompatSizeCompatModePolicy().clearSizeCompatMode();
+ activity.mAppCompatController.getSizeCompatModePolicy().clearSizeCompatMode();
// The per-package override forces the activity into a 3:2 aspect ratio
assertEquals(1200, activity.getBounds().height());
@@ -1531,7 +1531,7 @@ public class SizeCompatTests extends WindowTestsBase {
// After changing the orientation to portrait the override should be applied.
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- activity.mAppCompatController.getAppCompatSizeCompatModePolicy().clearSizeCompatMode();
+ activity.mAppCompatController.getSizeCompatModePolicy().clearSizeCompatMode();
// The per-package override forces the activity into a 3:2 aspect ratio
assertEquals(1200, activity.getBounds().height());
@@ -1554,7 +1554,7 @@ public class SizeCompatTests extends WindowTestsBase {
// After changing the orientation to landscape the override shouldn't be applied.
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
- activity.mAppCompatController.getAppCompatSizeCompatModePolicy().clearSizeCompatMode();
+ activity.mAppCompatController.getSizeCompatModePolicy().clearSizeCompatMode();
// The per-package override should have no effect
assertEquals(1200, activity.getBounds().height());
@@ -1754,7 +1754,7 @@ public class SizeCompatTests extends WindowTestsBase {
addWindowToActivity(mActivity);
// App should launch in fullscreen.
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
@@ -1769,7 +1769,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertTrue(rotatedDisplayBounds.width() < rotatedDisplayBounds.height());
// App should be in size compat.
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertDownScaled();
assertThat(mActivity.inSizeCompatMode()).isTrue();
@@ -1882,7 +1882,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertTrue(displayBounds.width() > displayBounds.height());
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertActivityMaxBoundsSandboxed();
@@ -1913,7 +1913,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertTrue(displayBounds.width() > displayBounds.height());
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
@@ -1943,7 +1943,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertTrue(displayBounds.width() > displayBounds.height());
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
@@ -1973,7 +1973,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertTrue(displayBounds.width() > displayBounds.height());
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
@@ -2070,7 +2070,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertTrue(displayBounds.width() > displayBounds.height());
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
@@ -2094,7 +2094,7 @@ 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.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFitted();
assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
@@ -2134,7 +2134,7 @@ 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.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFitted();
assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
@@ -2169,7 +2169,7 @@ public class SizeCompatTests extends WindowTestsBase {
final Rect activityBounds = new Rect(mActivity.getBounds());
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
// Checking that there is no size compat mode.
assertFitted();
@@ -2199,9 +2199,9 @@ public class SizeCompatTests extends WindowTestsBase {
.isUserAppAspectRatioFullscreenEnabled();
// Set user aspect ratio override
- spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides());
+ spyOn(mActivity.mAppCompatController.getAspectRatioOverrides());
doReturn(USER_MIN_ASPECT_RATIO_FULLSCREEN)
- .when(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides())
+ .when(mActivity.mAppCompatController.getAspectRatioOverrides())
.getUserMinAspectRatioOverrideCode();
prepareMinAspectRatio(mActivity, 16 / 9f, SCREEN_ORIENTATION_PORTRAIT);
@@ -2224,9 +2224,9 @@ public class SizeCompatTests extends WindowTestsBase {
.isUserAppAspectRatioFullscreenEnabled();
// Set user aspect ratio override
- spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides());
+ spyOn(mActivity.mAppCompatController.getAspectRatioOverrides());
doReturn(USER_MIN_ASPECT_RATIO_FULLSCREEN)
- .when(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides())
+ .when(mActivity.mAppCompatController.getAspectRatioOverrides())
.getUserMinAspectRatioOverrideCode();
prepareMinAspectRatio(mActivity, 16 / 9f, SCREEN_ORIENTATION_LANDSCAPE);
@@ -2244,9 +2244,9 @@ public class SizeCompatTests extends WindowTestsBase {
final int displayWidth = mDisplayContent.mBaseDisplayWidth;
final int displayHeight = mDisplayContent.mBaseDisplayHeight;
- spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides());
+ spyOn(mActivity.mAppCompatController.getAspectRatioOverrides());
doReturn(true).when(
- mActivity.mAppCompatController.getAppCompatAspectRatioOverrides())
+ mActivity.mAppCompatController.getAspectRatioOverrides())
.isSystemOverrideToFullscreenEnabled();
prepareMinAspectRatio(mActivity, 16 / 9f, SCREEN_ORIENTATION_PORTRAIT);
@@ -2264,9 +2264,9 @@ public class SizeCompatTests extends WindowTestsBase {
final int displayWidth = mDisplayContent.mBaseDisplayWidth;
final int displayHeight = mDisplayContent.mBaseDisplayHeight;
- spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides());
+ spyOn(mActivity.mAppCompatController.getAspectRatioOverrides());
doReturn(true).when(
- mActivity.mAppCompatController.getAppCompatAspectRatioOverrides())
+ mActivity.mAppCompatController.getAspectRatioOverrides())
.isSystemOverrideToFullscreenEnabled();
prepareMinAspectRatio(mActivity, 16 / 9f, SCREEN_ORIENTATION_LANDSCAPE);
@@ -2416,7 +2416,7 @@ public class SizeCompatTests extends WindowTestsBase {
boolean enabled) {
final ActivityRecord activity = getActivityBuilderWithoutTask().build();
final DesktopAppCompatAspectRatioPolicy desktopAppCompatAspectRatioPolicy =
- activity.mAppCompatController.getDesktopAppCompatAspectRatioPolicy();
+ activity.mAppCompatController.getDesktopAspectRatioPolicy();
spyOn(desktopAppCompatAspectRatioPolicy);
doReturn(enabled).when(desktopAppCompatAspectRatioPolicy)
.hasMinAspectRatioOverride(any());
@@ -2426,7 +2426,7 @@ public class SizeCompatTests extends WindowTestsBase {
doReturn(enabled).when(activity.mWmService.mAppCompatConfiguration)
.isUserAppAspectRatioSettingsEnabled();
final AppCompatAspectRatioOverrides aspectRatioOverrides =
- activity.mAppCompatController.getAppCompatAspectRatioOverrides();
+ activity.mAppCompatController.getAspectRatioOverrides();
spyOn(aspectRatioOverrides);
// Set user aspect ratio override.
doReturn(aspectRatio).when(aspectRatioOverrides).getUserMinAspectRatioOverrideCode();
@@ -2703,7 +2703,7 @@ public class SizeCompatTests extends WindowTestsBase {
final Rect activityBounds = new Rect(mActivity.getBounds());
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
// Checking that there is no size compat mode.
assertFitted();
@@ -2747,7 +2747,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode());
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
// Checking that there is no size compat mode.
assertFitted();
@@ -2782,7 +2782,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode());
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
// Checking that there is no size compat mode.
assertFitted();
@@ -2808,7 +2808,7 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
// Checking that there is no size compat mode.
assertFitted();
@@ -2834,7 +2834,7 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
// App should launch in fixed orientation letterbox.
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
// Checking that there is no size compat mode.
assertFitted();
@@ -2863,7 +2863,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertTrue(displayBounds.width() < displayBounds.height());
// App should be in size compat.
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertThat(mActivity.inSizeCompatMode()).isTrue();
assertEquals(activityBounds.width(), newActivityBounds.width());
@@ -2880,7 +2880,7 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
// App should launch in fullscreen.
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
// Activity inherits max bounds from TaskDisplayArea.
@@ -2894,7 +2894,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertTrue(rotatedDisplayBounds.width() > rotatedDisplayBounds.height());
// App should be in size compat.
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertDownScaled();
assertThat(mActivity.inSizeCompatMode()).isTrue();
@@ -2915,7 +2915,7 @@ public class SizeCompatTests extends WindowTestsBase {
// Portrait fixed app without max aspect.
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
@@ -2938,7 +2938,7 @@ 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.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(newActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(newActivity.inSizeCompatMode());
// Activity max bounds are sandboxed due to size compat mode.
@@ -2959,7 +2959,7 @@ public class SizeCompatTests extends WindowTestsBase {
// Portrait fixed app without max aspect.
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
@@ -2980,7 +2980,7 @@ public class SizeCompatTests extends WindowTestsBase {
// Portrait fixed app without max aspect.
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
@@ -3011,7 +3011,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertActivityMaxBoundsSandboxed();
// Activity bounds should be (1400 / 1.3 = 1076)x1400 with the app requested ratio.
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(newActivity.inSizeCompatMode());
assertEquals(displayBounds.height(), newActivityBounds.height());
@@ -3030,7 +3030,7 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
clearInvocations(mActivity);
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
@@ -3038,7 +3038,7 @@ public class SizeCompatTests extends WindowTestsBase {
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
// App should be in size compat.
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertThat(mActivity.inSizeCompatMode()).isTrue();
// Activity max bounds are sandboxed due to size compat mode.
@@ -3050,10 +3050,10 @@ public class SizeCompatTests extends WindowTestsBase {
// App still in size compat, and the bounds don't change.
final AppCompatSizeCompatModePolicy scmPolicy = mActivity.mAppCompatController
- .getAppCompatSizeCompatModePolicy();
+ .getSizeCompatModePolicy();
spyOn(scmPolicy);
verify(scmPolicy, never()).clearSizeCompatMode();
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertThat(mActivity.inSizeCompatMode()).isTrue();
assertEquals(activityBounds, mActivity.getBounds());
@@ -3071,7 +3071,7 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
// In fixed orientation letterbox
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertActivityMaxBoundsSandboxed();
@@ -3080,7 +3080,7 @@ public class SizeCompatTests extends WindowTestsBase {
rotateDisplay(display, ROTATION_90);
// App should be in size compat.
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertThat(mActivity.inSizeCompatMode()).isTrue();
assertActivityMaxBoundsSandboxed();
@@ -3089,7 +3089,7 @@ public class SizeCompatTests extends WindowTestsBase {
rotateDisplay(display, ROTATION_180);
// In activity letterbox
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertActivityMaxBoundsSandboxed();
@@ -3108,7 +3108,7 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_LANDSCAPE);
// In fixed orientation letterbox
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertActivityMaxBoundsSandboxed();
@@ -3117,7 +3117,7 @@ public class SizeCompatTests extends WindowTestsBase {
rotateDisplay(display, ROTATION_90);
// App should be in size compat.
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertDownScaled();
assertActivityMaxBoundsSandboxed();
@@ -3126,7 +3126,7 @@ public class SizeCompatTests extends WindowTestsBase {
rotateDisplay(display, ROTATION_180);
// In fixed orientation letterbox
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertActivityMaxBoundsSandboxed();
@@ -3325,7 +3325,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(ORIENTATION_PORTRAIT, mTask.getConfiguration().orientation);
assertEquals(ORIENTATION_LANDSCAPE, mActivity.getConfiguration().orientation);
assertFitted();
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertActivityMaxBoundsSandboxed();
@@ -3352,7 +3352,7 @@ public class SizeCompatTests extends WindowTestsBase {
// Resizable activity is not in size compat mode but in the letterbox for fixed orientation.
assertFitted();
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
}
@@ -3389,7 +3389,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(ORIENTATION_PORTRAIT, mTask.getConfiguration().orientation);
assertEquals(ORIENTATION_PORTRAIT, mActivity.getConfiguration().orientation);
assertFitted();
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertActivityMaxBoundsSandboxed();
@@ -3889,14 +3889,15 @@ public class SizeCompatTests extends WindowTestsBase {
private void recomputeNaturalConfigurationOfUnresizableActivity() {
// Recompute the natural configuration of the non-resizable activity and the split screen.
- mActivity.mAppCompatController.getAppCompatSizeCompatModePolicy().clearSizeCompatMode();
+ mActivity.mAppCompatController.getSizeCompatModePolicy().clearSizeCompatMode();
// Draw letterbox.
- mActivity.setVisible(false);
- mActivity.mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_OPEN);
- mActivity.mDisplayContent.mOpeningApps.add(mActivity);
+ mActivity.ensureActivityConfiguration();
addWindowToActivity(mActivity);
mActivity.mRootWindowContainer.performSurfacePlacement();
+
+ // Verify mAppCompatDisplayInsets is created after recomputing.
+ assertTrue(mActivity.providesMaxBounds());
}
private void assertLetterboxSurfacesDrawnBetweenActivityAndParentBounds(Rect parentBounds) {
@@ -4031,7 +4032,7 @@ 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.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(activity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertNotNull(appBounds);
assertEquals(displayBounds.width(), appBounds.width());
@@ -4063,7 +4064,7 @@ public class SizeCompatTests extends WindowTestsBase {
final Rect bounds = activity.getBounds();
// Activity should be letterboxed and should have portrait app bounds
- assertTrue(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(activity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertTrue(bounds.height() > bounds.width());
}
@@ -4098,7 +4099,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertNotNull(activity.getAppCompatDisplayInsets());
// Activity is not letterboxed for fixed orientation because orientation is respected
// with insets, and should not be in size compat mode
- assertFalse(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(activity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(activity.inSizeCompatMode());
}
@@ -4357,7 +4358,7 @@ public class SizeCompatTests extends WindowTestsBase {
Configuration parentConfig = mActivity.getParent().getConfiguration();
final AppCompatAspectRatioOverrides aspectRatioOverrides =
- mActivity.mAppCompatController.getAppCompatAspectRatioOverrides();
+ mActivity.mAppCompatController.getAspectRatioOverrides();
float actual = aspectRatioOverrides.getFixedOrientationLetterboxAspectRatio(parentConfig);
float expected = aspectRatioOverrides.getSplitScreenAspectRatio();
@@ -4497,14 +4498,14 @@ public class SizeCompatTests extends WindowTestsBase {
.isUserAppAspectRatioSettingsEnabled();
final AppCompatController appCompatController = mActivity.mAppCompatController;
final AppCompatAspectRatioOverrides aspectRatioOverrides =
- appCompatController.getAppCompatAspectRatioOverrides();
+ appCompatController.getAspectRatioOverrides();
spyOn(aspectRatioOverrides);
// Set user aspect ratio override.
doReturn(USER_MIN_ASPECT_RATIO_16_9).when(aspectRatioOverrides)
.getUserMinAspectRatioOverrideCode();
prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_PORTRAIT, /* isUnresizable= */ false);
- assertFalse(appCompatController.getAppCompatAspectRatioPolicy().isAspectRatioApplied());
+ assertFalse(appCompatController.getAspectRatioPolicy().isAspectRatioApplied());
}
@Test
@@ -4520,14 +4521,14 @@ public class SizeCompatTests extends WindowTestsBase {
.isUserAppAspectRatioSettingsEnabled();
final AppCompatController appCompatController = mActivity.mAppCompatController;
final AppCompatAspectRatioOverrides aspectRatioOverrides =
- appCompatController.getAppCompatAspectRatioOverrides();
+ appCompatController.getAspectRatioOverrides();
spyOn(aspectRatioOverrides);
// Set user aspect ratio override.
doReturn(USER_MIN_ASPECT_RATIO_16_9).when(aspectRatioOverrides)
.getUserMinAspectRatioOverrideCode();
prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_PORTRAIT, /* isUnresizable= */ true);
- assertTrue(appCompatController.getAppCompatAspectRatioPolicy().isAspectRatioApplied());
+ assertTrue(appCompatController.getAspectRatioPolicy().isAspectRatioApplied());
}
@Test
@@ -4540,8 +4541,7 @@ public class SizeCompatTests extends WindowTestsBase {
setUpDisplaySizeWithApp(2500, 1600, taskBuilder);
prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_PORTRAIT, /* isUnresizable= */ false);
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
- .isAspectRatioApplied());
+ assertFalse(mActivity.mAppCompatController.getAspectRatioPolicy().isAspectRatioApplied());
}
@Test
@@ -4554,8 +4554,7 @@ public class SizeCompatTests extends WindowTestsBase {
setUpDisplaySizeWithApp(2500, 1600, taskBuilder);
prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_PORTRAIT, /* isUnresizable= */ true);
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
- .isAspectRatioApplied());
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy().isAspectRatioApplied());
}
private void assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
@@ -4604,7 +4603,7 @@ public class SizeCompatTests extends WindowTestsBase {
verifyLogAppCompatState(mActivity, APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED);
prepareUnresizable(mActivity, /* maxAspect= */ 2, SCREEN_ORIENTATION_PORTRAIT);
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertTrue(mActivity.areBoundsLetterboxed());
@@ -4621,7 +4620,7 @@ 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.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertTrue(mActivity.areBoundsLetterboxed());
@@ -4649,7 +4648,7 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertTrue(mActivity.areBoundsLetterboxed());
@@ -4668,7 +4667,7 @@ public class SizeCompatTests extends WindowTestsBase {
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertTrue(mActivity.inSizeCompatMode());
assertTrue(mActivity.areBoundsLetterboxed());
@@ -4730,7 +4729,7 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
assertFalse(mActivity.isEligibleForLetterboxEducation());
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
}
@@ -4789,7 +4788,7 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
assertTrue(mActivity.isEligibleForLetterboxEducation());
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
}
@@ -4804,7 +4803,7 @@ public class SizeCompatTests extends WindowTestsBase {
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
assertTrue(mActivity.isEligibleForLetterboxEducation());
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertTrue(mActivity.inSizeCompatMode());
}
@@ -5007,13 +5006,13 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, mActivity.getOverrideOrientation());
assertEquals(mActivity.getTask().getBounds(), mActivity.getBounds());
final AppCompatAspectRatioPolicy aspectRatioPolicy = mActivity.mAppCompatController
- .getAppCompatAspectRatioPolicy();
+ .getAspectRatioPolicy();
assertEquals(0, aspectRatioPolicy.getMaxAspectRatio(), 0 /* delta */);
assertEquals(0, aspectRatioPolicy.getMinAspectRatio(), 0 /* delta */);
// Compat override can still take effect.
final AppCompatAspectRatioOverrides aspectRatioOverrides =
- mActivity.mAppCompatController.getAppCompatAspectRatioOverrides();
+ mActivity.mAppCompatController.getAspectRatioOverrides();
spyOn(aspectRatioOverrides);
doReturn(true).when(aspectRatioOverrides).shouldOverrideMinAspectRatio();
assertEquals(minAspect, aspectRatioPolicy.getMinAspectRatio(), 0 /* delta */);
@@ -5090,7 +5089,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(origDensity, mActivity.getConfiguration().densityDpi);
// Activity should exit size compat with new density.
- mActivity.mAppCompatController.getAppCompatSizeCompatModePolicy().clearSizeCompatMode();
+ mActivity.mAppCompatController.getSizeCompatModePolicy().clearSizeCompatMode();
assertFitted();
assertEquals(newDensity, mActivity.getConfiguration().densityDpi);
@@ -5274,7 +5273,7 @@ public class SizeCompatTests extends WindowTestsBase {
activity.setRequestedOrientation(screenOrientation);
}
// Make sure to use the provided configuration to construct the size compat fields.
- activity.mAppCompatController.getAppCompatSizeCompatModePolicy().clearSizeCompatMode();
+ activity.mAppCompatController.getSizeCompatModePolicy().clearSizeCompatMode();
activity.ensureActivityConfiguration();
// Make sure the display configuration reflects the change of activity.
if (activity.mDisplayContent.updateOrientation()) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index a12831e1ccf1..a95093d7e113 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -43,6 +43,7 @@ import static org.mockito.Mockito.CALLS_REAL_METHODS;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
+import android.annotation.Nullable;
import android.app.ActivityManagerInternal;
import android.app.ActivityThread;
import android.app.AppOpsManager;
@@ -67,7 +68,6 @@ import android.os.Looper;
import android.os.PowerManager;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
-import android.os.StrictMode;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
@@ -75,7 +75,6 @@ import android.util.Log;
import android.view.DisplayInfo;
import android.view.InputChannel;
import android.view.SurfaceControl;
-import android.window.ConfigurationChangeSetting;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.internal.os.BackgroundThread;
@@ -96,11 +95,9 @@ import com.android.server.input.InputManagerService;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerService;
import com.android.server.policy.PermissionPolicyInternal;
-import com.android.server.policy.WindowManagerPolicy;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.testutils.StubTransaction;
import com.android.server.uri.UriGrantsManagerInternal;
-import com.android.window.flags.Flags;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
@@ -144,13 +141,15 @@ public class SystemServicesTestRule implements TestRule {
private ActivityTaskManagerService mAtmService;
private WindowManagerService mWmService;
private InputManagerService mImService;
- private Runnable mOnBeforeServicesCreated;
+ @Nullable
+ private final Runnable mOnBeforeServicesCreated;
+
/**
* Spied {@link SurfaceControl.Transaction} class than can be used to verify calls.
*/
SurfaceControl.Transaction mTransaction;
- public SystemServicesTestRule(Runnable onBeforeServicesCreated) {
+ public SystemServicesTestRule(@Nullable Runnable onBeforeServicesCreated) {
mOnBeforeServicesCreated = onBeforeServicesCreated;
}
@@ -398,15 +397,13 @@ public class SystemServicesTestRule implements TestRule {
}
private void setUpWindowManagerService() {
- TestWindowManagerPolicy wmPolicy = new TestWindowManagerPolicy();
- TestDisplayWindowSettingsProvider testDisplayWindowSettingsProvider =
- new TestDisplayWindowSettingsProvider();
- // Suppress StrictMode violation (DisplayWindowSettings) to avoid log flood.
- DisplayThread.getHandler().post(StrictMode::allowThreadDiskWritesMask);
- mWmService = WindowManagerService.main(
- mContext, mImService, false, wmPolicy, mAtmService,
- testDisplayWindowSettingsProvider, StubTransaction::new,
- MockSurfaceControlBuilder::new, mAppCompat);
+ // Use a spied Transaction class to prevent native code calls and verify interactions.
+ mTransaction = spy(StubTransaction.class);
+
+ mWmService = WindowManagerServiceTestSupport.setUpService(mContext, mImService,
+ new TestWindowManagerPolicy(), mAtmService, new TestDisplayWindowSettingsProvider(),
+ mTransaction, new MockSurfaceControlBuilder(), mAppCompat);
+
spyOn(mWmService);
spyOn(mWmService.mRoot);
// Invoked during {@link ActivityStack} creation.
@@ -418,10 +415,6 @@ public class SystemServicesTestRule implements TestRule {
spyOn(mWmService.mDisplayWindowSettings);
spyOn(mWmService.mDisplayWindowSettingsProvider);
- // Setup factory classes to prevent calls to native code.
- mTransaction = spy(StubTransaction.class);
- // Return a spied Transaction class than can be used to verify calls.
- mWmService.mTransactionFactory = () -> mTransaction;
mWmService.mSurfaceAnimationRunner = new SurfaceAnimationRunner(
null, null, mTransaction, mWmService.mPowerManagerInternal);
@@ -488,12 +481,12 @@ public class SystemServicesTestRule implements TestRule {
}
private static void tearDownLocalServices() {
+ WindowManagerServiceTestSupport.tearDownService();
+
LocalServices.removeServiceForTest(DisplayManagerInternal.class);
LocalServices.removeServiceForTest(PowerManagerInternal.class);
LocalServices.removeServiceForTest(ActivityManagerInternal.class);
LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
- LocalServices.removeServiceForTest(WindowManagerInternal.class);
- LocalServices.removeServiceForTest(WindowManagerPolicy.class);
LocalServices.removeServiceForTest(PackageManagerInternal.class);
LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
LocalServices.removeServiceForTest(PermissionPolicyInternal.class);
@@ -501,12 +494,7 @@ public class SystemServicesTestRule implements TestRule {
LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
LocalServices.removeServiceForTest(UserManagerInternal.class);
- LocalServices.removeServiceForTest(ImeTargetVisibilityPolicy.class);
LocalServices.removeServiceForTest(GrammaticalInflectionManagerInternal.class);
- if (Flags.condenseConfigurationChangeForSimpleMode()) {
- LocalServices.removeServiceForTest(
- ConfigurationChangeSetting.ConfigurationChangeSettingInternal.class);
- }
}
Description getDescription() {
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 ef58498b351c..546ecc6e38a5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -36,6 +36,7 @@ import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_TOP_OF_TAS
import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ANIMATION_PARAMS;
+import static android.window.TaskFragmentOperation.OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_DIM_ON_TASK;
import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE;
@@ -1911,6 +1912,53 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
OP_TYPE_REORDER_TO_TOP_OF_TASK);
}
+ @Test
+ public void testApplyTransaction_setCanAffectSystemUiFlags() {
+ mController.unregisterOrganizer(mIOrganizer);
+ registerTaskFragmentOrganizer(mIOrganizer, true /* isSystemOrganizer */);
+
+ final Task task = createTask(mDisplayContent);
+ final TaskFragment tf = createTaskFragment(task);
+
+ // Setting the flag to false.
+ TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
+ OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS).setBooleanValue(false).build();
+ mTransaction.addTaskFragmentOperation(tf.getFragmentToken(), operation);
+
+ assertApplyTransactionAllowed(mTransaction);
+
+ verify(tf).setCanAffectSystemUiFlags(false);
+
+ // Setting the flag back to true.
+ operation = new TaskFragmentOperation.Builder(
+ OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS).setBooleanValue(true).build();
+ mTransaction.addTaskFragmentOperation(tf.getFragmentToken(), operation);
+
+ assertApplyTransactionAllowed(mTransaction);
+
+ verify(tf).setCanAffectSystemUiFlags(true);
+ }
+
+ @Test
+ public void testApplyTransaction_setCanAffectSystemUiFlags_failsIfNotSystemOrganizer() {
+ final Task task = createTask(mDisplayContent);
+ final TaskFragment tf = createTaskFragment(task);
+
+ TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
+ OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS).setBooleanValue(false).build();
+ mTransaction
+ .addTaskFragmentOperation(tf.getFragmentToken(), operation)
+ .setErrorCallbackToken(mErrorToken);
+
+ assertApplyTransactionAllowed(mTransaction);
+
+ // The pending event will be dispatched on the handler (from requestTraversal).
+ waitHandlerIdle(mWm.mAnimationHandler);
+
+ assertTaskFragmentErrorTransaction(OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS,
+ SecurityException.class);
+ }
+
@NonNull
private ActivityRecord setupUntrustedEmbeddingPipReparent() {
final int pid = Binder.getCallingPid();
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 299717393028..0d9772492e59 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -759,13 +759,13 @@ public class TaskFragmentTest extends WindowTestsBase {
// Assert fixed orientation request is ignored for activity in ActivityEmbedding split.
activity0.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
- assertFalse(activity0.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(activity0.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertEquals(SCREEN_ORIENTATION_UNSET, task.getOrientation());
activity1.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
- assertFalse(activity1.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(activity1.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertEquals(SCREEN_ORIENTATION_UNSET, task.getOrientation());
@@ -773,9 +773,9 @@ public class TaskFragmentTest extends WindowTestsBase {
mDisplayContent.setIgnoreOrientationRequest(true);
task.onConfigurationChanged(task.getParent().getConfiguration());
- assertFalse(activity0.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(activity0.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
- assertFalse(activity1.mAppCompatController.getAppCompatAspectRatioPolicy()
+ assertFalse(activity1.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
assertEquals(SCREEN_ORIENTATION_UNSET, task.getOrientation());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index 1e0cef0514d8..1e16c97de647 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -113,7 +113,7 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase {
mSnapshotPersistQueue = new SnapshotPersistQueue();
PersistInfoProvider provider =
TaskSnapshotController.createPersistInfoProvider(mWm, userId -> FILES_DIR);
- mPersister = new TaskSnapshotPersister(mSnapshotPersistQueue, provider);
+ mPersister = new TaskSnapshotPersister(mSnapshotPersistQueue, provider, false);
mLoader = new AppSnapshotLoader(provider);
mSnapshotPersistQueue.start();
}
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 1febc9fb4742..38d3d2fec942 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -684,9 +684,7 @@ public class TaskTests extends WindowTestsBase {
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
Task task = rootTask.getBottomMostTask();
task.getRootActivity().setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
- DisplayInfo info = new DisplayInfo();
- display.mDisplay.getDisplayInfo(info);
- final Rect fullScreenBounds = new Rect(0, 0, info.logicalWidth, info.logicalHeight);
+ final Rect fullScreenBounds = new Rect(display.getBounds());
final Rect freeformBounds = new Rect(fullScreenBounds);
freeformBounds.inset((int) (freeformBounds.width() * 0.2),
(int) (freeformBounds.height() * 0.2));
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransparentPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/TransparentPolicyTest.java
index f1180ff93edb..9cd302e71d3b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransparentPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransparentPolicyTest.java
@@ -354,7 +354,7 @@ public class TransparentPolicyTest extends WindowTestsBase {
ta.launchTransparentActivityInTask();
a.assertNotNullOnTopActivity(ActivityRecord::getAppCompatDisplayInsets);
a.applyToTopActivity((top) -> {
- top.mAppCompatController.getAppCompatSizeCompatModePolicy()
+ top.mAppCompatController.getSizeCompatModePolicy()
.clearSizeCompatMode();
});
a.assertNullOnTopActivity(ActivityRecord::getAppCompatDisplayInsets);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTestSupport.kt b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTestSupport.kt
new file mode 100644
index 000000000000..a165d20eb5c1
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTestSupport.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 android.content.Context
+import android.os.StrictMode
+import android.view.SurfaceControl
+import android.window.ConfigurationChangeSetting
+import com.android.server.DisplayThread
+import com.android.server.LocalServices
+import com.android.server.input.InputManagerService
+import com.android.server.policy.WindowManagerPolicy
+import com.android.window.flags.Flags
+
+/**
+ * Provides support for tests that require a [WindowManagerService].
+ *
+ * It provides functionalities for setting up and tearing down the service with proper dependencies,
+ * which can be used across different test modules.
+ */
+object WindowManagerServiceTestSupport {
+
+ /**
+ * Sets up and initializes a [WindowManagerService] instance with the provided dependencies.
+ *
+ * This method constructs a [WindowManagerService] using the provided dependencies for testing.
+ * It's marked as `internal` due to the package-private classes [DisplayWindowSettingsProvider]
+ * and [AppCompatConfiguration]. The `@JvmName` annotation is used to bypass name mangling and
+ * allow access from Java via `WindowManagerServiceTestSupport.setUpService`.
+ *
+ * **Important:** Before calling this method, ensure that any previous [WindowManagerService]
+ * instance and its related services are properly torn down. In your test's setup, it is
+ * recommended to call [tearDownService] before calling [setUpService] to handle cases where a
+ * previous test might have crashed and left services in an inconsistent state. This is crucial
+ * for test reliability.
+ *
+ * Example usage in a test's `setUp()` method:
+ * ```
+ * @Before
+ * fun setUp() {
+ * WindowManagerServiceTestSupport.tearDownService() // Clean up before setup.
+ * mWindowManagerService = WindowManagerServiceTestSupport.setUpService(...)
+ * // ... rest of your setup logic ...
+ * }
+ * ```
+ *
+ * @param context the [Context] for the service.
+ * @param im the [InputManagerService] to use.
+ * @param policy the [WindowManagerPolicy] to use.
+ * @param atm the [ActivityTaskManagerService] to use.
+ * @param displayWindowSettingsProvider the [DisplayWindowSettingsProvider] to use.
+ * @param surfaceControlTransaction the [SurfaceControl.Transaction] instance to use.
+ * @param surfaceControlBuilder the [SurfaceControl.Builder] instance to use.
+ * @param appCompat the [AppCompatConfiguration] to use.
+ * @return the created [WindowManagerService] instance.
+ */
+ @JvmStatic
+ @JvmName("setUpService")
+ internal fun setUpService(
+ context: Context,
+ im: InputManagerService,
+ policy: WindowManagerPolicy,
+ atm: ActivityTaskManagerService,
+ displayWindowSettingsProvider: DisplayWindowSettingsProvider,
+ surfaceControlTransaction: SurfaceControl.Transaction,
+ surfaceControlBuilder: SurfaceControl.Builder,
+ appCompat: AppCompatConfiguration,
+ ): WindowManagerService {
+ // Suppress StrictMode violation (DisplayWindowSettings) to avoid log flood.
+ DisplayThread.getHandler().post { StrictMode.allowThreadDiskWritesMask() }
+
+ return WindowManagerService.main(
+ context,
+ im,
+ false, /* showBootMsgs */
+ policy,
+ atm,
+ displayWindowSettingsProvider,
+ { surfaceControlTransaction },
+ { surfaceControlBuilder },
+ appCompat,
+ )
+ }
+
+ /** Tears down the [WindowManagerService] and removes related local services. */
+ @JvmStatic
+ fun tearDownService() {
+ LocalServices.removeServiceForTest(WindowManagerPolicy::class.java)
+ LocalServices.removeServiceForTest(WindowManagerInternal::class.java)
+ LocalServices.removeServiceForTest(ImeTargetVisibilityPolicy::class.java)
+
+ if (Flags.condenseConfigurationChangeForSimpleMode()) {
+ LocalServices.removeServiceForTest(
+ ConfigurationChangeSetting.ConfigurationChangeSettingInternal::class.java,
+ )
+ }
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index ab9abfc4a876..f6f473b4964d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -855,7 +855,6 @@ public class WindowStateTests extends WindowTestsBase {
startingApp.updateResizingWindowIfNeeded();
assertTrue(mWm.mResizingWindows.contains(startingApp));
assertTrue(startingApp.isDrawn());
- assertFalse(startingApp.getOrientationChanging());
// Even if the display is frozen, invisible requested window should not be affected.
mWm.startFreezingDisplay(0, 0, mDisplayContent);
@@ -873,7 +872,6 @@ public class WindowStateTests extends WindowTestsBase {
win.updateResizingWindowIfNeeded();
assertThat(mWm.mResizingWindows).contains(win);
- assertTrue(win.getOrientationChanging());
mWm.mResizingWindows.remove(win);
spyOn(win.mClient);
@@ -892,7 +890,6 @@ public class WindowStateTests extends WindowTestsBase {
// Even "resized" throws remote exception, it is still considered as reported. So the window
// shouldn't be resized again (which may block unfreeze in real case).
assertThat(mWm.mResizingWindows).doesNotContain(win);
- assertFalse(win.getOrientationChanging());
}
@Test
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java b/services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java
index 819e73df955b..6dda7ea3eb59 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java
@@ -48,6 +48,13 @@ public abstract class UsbACTerminal extends UsbACInterface {
return mAssocTerminal;
}
+ public boolean isInputTerminal() {
+ return mTerminalType == UsbTerminalTypes.TERMINAL_IN_MIC
+ || mTerminalType == UsbTerminalTypes.TERMINAL_BIDIR_HEADSET
+ || mTerminalType == UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED
+ || mTerminalType == UsbTerminalTypes.TERMINAL_EXTERN_LINE;
+ }
+
@Override
public int parseRawDescriptors(ByteStream stream) {
mTerminalID = stream.getByte();
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
index ba178845a536..bfa4ecd71f5a 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
@@ -524,27 +524,21 @@ public final class UsbDescriptorParser {
* @hide
*/
public boolean hasMic() {
- boolean hasMic = false;
-
ArrayList<UsbDescriptor> acDescriptors =
getACInterfaceDescriptors(UsbACInterface.ACI_INPUT_TERMINAL,
UsbACInterface.AUDIO_AUDIOCONTROL);
for (UsbDescriptor descriptor : acDescriptors) {
if (descriptor instanceof UsbACTerminal) {
UsbACTerminal inDescr = (UsbACTerminal) descriptor;
- if (inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_IN_MIC
- || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_HEADSET
- || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED
- || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_EXTERN_LINE) {
- hasMic = true;
- break;
+ if (inDescr.isInputTerminal()) {
+ return true;
}
} else {
Log.w(TAG, "Undefined Audio Input terminal l: " + descriptor.getLength()
+ " t:0x" + Integer.toHexString(descriptor.getType()));
}
}
- return hasMic;
+ return false;
}
/**
@@ -913,18 +907,20 @@ public final class UsbDescriptorParser {
float probability = 0.0f;
- // Look for a microphone
- boolean hasMic = hasMic();
-
// Look for a "speaker"
boolean hasSpeaker = hasSpeaker();
- if (hasMic && hasSpeaker) {
- probability += 0.75f;
- }
-
- if (hasMic && hasHIDInterface()) {
- probability += 0.25f;
+ if (hasMic()) {
+ if (hasSpeaker) {
+ probability += 0.75f;
+ }
+ if (hasHIDInterface()) {
+ probability += 0.25f;
+ }
+ if (getMaximumInputChannelCount() > 1) {
+ // A headset is more likely to only support mono capture.
+ probability -= 0.25f;
+ }
}
return probability;
@@ -935,9 +931,11 @@ public final class UsbDescriptorParser {
* headset. The probability range is between 0.0f (definitely NOT a headset) and
* 1.0f (definitely IS a headset). A probability of 0.75f seems sufficient
* to count on the peripheral being a headset.
+ * To align with the output device type, only treat the device as input headset if it is
+ * an output headset.
*/
public boolean isInputHeadset() {
- return getInputHeadsetProbability() >= IN_HEADSET_TRIGGER;
+ return getInputHeadsetProbability() >= IN_HEADSET_TRIGGER && isOutputHeadset();
}
// TODO: Up/Downmix process descriptor is not yet parsed, which may affect the result here.
@@ -952,6 +950,32 @@ public final class UsbDescriptorParser {
return maxChannelCount;
}
+ private int getMaximumInputChannelCount() {
+ int maxChannelCount = 0;
+ ArrayList<UsbDescriptor> acDescriptors =
+ getACInterfaceDescriptors(UsbACInterface.ACI_INPUT_TERMINAL,
+ UsbACInterface.AUDIO_AUDIOCONTROL);
+ for (UsbDescriptor descriptor : acDescriptors) {
+ if (!(descriptor instanceof UsbACTerminal)) {
+ continue;
+ }
+ UsbACTerminal inDescr = (UsbACTerminal) descriptor;
+ if (!inDescr.isInputTerminal()) {
+ continue;
+ }
+ // For an input terminal, it should at lease has 1 channel.
+ // Comparing the max channel count with 1 here in case the USB device doesn't report
+ // audio channel cluster.
+ maxChannelCount = Math.max(maxChannelCount, 1);
+ if (!(descriptor instanceof UsbAudioChannelCluster)) {
+ continue;
+ }
+ maxChannelCount = Math.max(maxChannelCount,
+ ((UsbAudioChannelCluster) descriptor).getChannelCount());
+ }
+ return maxChannelCount;
+ }
+
/**
* @hide
*/
diff --git a/tests/CompanionDeviceMultiDeviceTests/client/Android.bp b/tests/CompanionDeviceMultiDeviceTests/client/Android.bp
index ce63fe89fe2e..02b639109931 100644
--- a/tests/CompanionDeviceMultiDeviceTests/client/Android.bp
+++ b/tests/CompanionDeviceMultiDeviceTests/client/Android.bp
@@ -45,7 +45,6 @@ android_test {
],
optimize: {
- proguard_compatibility: true,
proguard_flags_files: ["proguard.flags"],
},
}
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 0824874f2a36..9e9d014c622d 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
@@ -280,11 +280,20 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) :
.waitForAndVerify()
}
- /** Click close button on the app header for the given app. */
- fun closeDesktopApp(wmHelper: WindowManagerStateHelper, device: UiDevice) {
- val caption = getCaptionForTheApp(wmHelper, device)
- val closeButton = caption?.children?.find { it.resourceName.endsWith(CLOSE_BUTTON) }
- closeButton?.click()
+ /** Close a desktop app by clicking the close button on the app header for the given app or by
+ * pressing back. */
+ fun closeDesktopApp(
+ wmHelper: WindowManagerStateHelper,
+ device: UiDevice,
+ usingBackNavigation: Boolean = false
+ ) {
+ if (usingBackNavigation) {
+ device.pressBack()
+ } else {
+ val caption = getCaptionForTheApp(wmHelper, device)
+ val closeButton = caption?.children?.find { it.resourceName.endsWith(CLOSE_BUTTON) }
+ closeButton?.click()
+ }
wmHelper
.StateSyncBuilder()
.withAppTransitionIdle()
diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
index 8c04f647fb2f..e0532633d40b 100644
--- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
@@ -736,30 +736,6 @@ class KeyGestureControllerTests {
intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
),
TestData(
- "META + ALT + '-' -> Magnification Zoom Out",
- intArrayOf(
- KeyEvent.KEYCODE_META_LEFT,
- KeyEvent.KEYCODE_ALT_LEFT,
- KeyEvent.KEYCODE_MINUS
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_ZOOM_OUT,
- intArrayOf(KeyEvent.KEYCODE_MINUS),
- KeyEvent.META_META_ON or KeyEvent.META_ALT_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
- "META + ALT + '=' -> Magnification Zoom In",
- intArrayOf(
- KeyEvent.KEYCODE_META_LEFT,
- KeyEvent.KEYCODE_ALT_LEFT,
- KeyEvent.KEYCODE_EQUALS
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_ZOOM_IN,
- intArrayOf(KeyEvent.KEYCODE_EQUALS),
- KeyEvent.META_META_ON or KeyEvent.META_ALT_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
"META + ALT + M -> Toggle Magnification",
intArrayOf(
KeyEvent.KEYCODE_META_LEFT,
@@ -784,54 +760,6 @@ class KeyGestureControllerTests {
intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
),
TestData(
- "META + ALT + 'Down' -> Magnification Pan Down",
- intArrayOf(
- KeyEvent.KEYCODE_META_LEFT,
- KeyEvent.KEYCODE_ALT_LEFT,
- KeyEvent.KEYCODE_DPAD_DOWN
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_PAN_DOWN,
- intArrayOf(KeyEvent.KEYCODE_DPAD_DOWN),
- KeyEvent.META_META_ON or KeyEvent.META_ALT_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
- "META + ALT + 'Up' -> Magnification Pan Up",
- intArrayOf(
- KeyEvent.KEYCODE_META_LEFT,
- KeyEvent.KEYCODE_ALT_LEFT,
- KeyEvent.KEYCODE_DPAD_UP
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_PAN_UP,
- intArrayOf(KeyEvent.KEYCODE_DPAD_UP),
- KeyEvent.META_META_ON or KeyEvent.META_ALT_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
- "META + ALT + 'Left' -> Magnification Pan Left",
- intArrayOf(
- KeyEvent.KEYCODE_META_LEFT,
- KeyEvent.KEYCODE_ALT_LEFT,
- KeyEvent.KEYCODE_DPAD_LEFT
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_PAN_LEFT,
- intArrayOf(KeyEvent.KEYCODE_DPAD_LEFT),
- KeyEvent.META_META_ON or KeyEvent.META_ALT_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
- "META + ALT + 'Right' -> Magnification Pan Right",
- intArrayOf(
- KeyEvent.KEYCODE_META_LEFT,
- KeyEvent.KEYCODE_ALT_LEFT,
- KeyEvent.KEYCODE_DPAD_RIGHT
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFICATION_PAN_RIGHT,
- intArrayOf(KeyEvent.KEYCODE_DPAD_RIGHT),
- KeyEvent.META_META_ON or KeyEvent.META_ALT_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
"META + ALT + 'V' -> Toggle Voice Access",
intArrayOf(
KeyEvent.KEYCODE_META_LEFT,
diff --git a/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml b/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml
index 99106ad37783..5d488410aef7 100644
--- a/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml
+++ b/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml
@@ -5,7 +5,7 @@
</domain>
<domain> developer.android.com </domain>
<pin-set>
- <pin digest="SHA-256"> zCTnfLwLKbS9S2sbp+uFz4KZOocFvXxkV06Ce9O5M2w= </pin>
+ <pin digest="SHA-256"> YPtHaftLw6/0vnc2BnNKGF54xiCA28WFcccjkA4ypCM= </pin>
</pin-set>
</domain-config>
</network-security-config>
diff --git a/tests/NetworkSecurityConfigTest/res/xml/nested_domains.xml b/tests/NetworkSecurityConfigTest/res/xml/nested_domains.xml
index 232f88ff6cc9..731f0f041042 100644
--- a/tests/NetworkSecurityConfigTest/res/xml/nested_domains.xml
+++ b/tests/NetworkSecurityConfigTest/res/xml/nested_domains.xml
@@ -9,7 +9,7 @@
<domain-config>
<domain>developer.android.com</domain>
<pin-set>
- <pin digest="SHA-256">zCTnfLwLKbS9S2sbp+uFz4KZOocFvXxkV06Ce9O5M2w=</pin>
+ <pin digest="SHA-256">YPtHaftLw6/0vnc2BnNKGF54xiCA28WFcccjkA4ypCM=</pin>
</pin-set>
</domain-config>
</domain-config>
diff --git a/tests/NetworkSecurityConfigTest/res/xml/pins1.xml b/tests/NetworkSecurityConfigTest/res/xml/pins1.xml
index 7cc81b0101f1..2e49188ec4dc 100644
--- a/tests/NetworkSecurityConfigTest/res/xml/pins1.xml
+++ b/tests/NetworkSecurityConfigTest/res/xml/pins1.xml
@@ -3,7 +3,7 @@
<domain-config>
<domain>android.com</domain>
<pin-set>
- <pin digest="SHA-256">zCTnfLwLKbS9S2sbp+uFz4KZOocFvXxkV06Ce9O5M2w=</pin>
+ <pin digest="SHA-256">YPtHaftLw6/0vnc2BnNKGF54xiCA28WFcccjkA4ypCM=</pin>
</pin-set>
</domain-config>
</network-security-config>
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
index c6fe06858e3f..6207a6295ebf 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
@@ -40,9 +40,9 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> {
super(Activity.class);
}
- // SHA-256 of the GTS intermediate CA (CN = GTS CA 1C3) for android.com (as of 09/2023).
+ // SHA-256 of the GTS intermediate CA (CN = WR2) for android.com (as of 01/2025).
private static final byte[] GTS_INTERMEDIATE_SPKI_SHA256 =
- hexToBytes("cc24e77cbc0b29b4bd4b6b1ba7eb85cf82993a8705bd7c64574e827bd3b9336c");
+ hexToBytes("60fb4769fb4bc3aff4be773606734a185e78c62080dbc58571c723900e32a423");
private static final byte[] TEST_CA_BYTES
= hexToBytes(
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java
index 39b5cb4c4f0d..e140d1a0a94c 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java
@@ -55,6 +55,7 @@ public final class TestUtils {
throws Exception {
URL url = new URL("https://" + host + ":" + port);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
+ connection.setInstanceFollowRedirects(false);
connection.setSSLSocketFactory(context.getSocketFactory());
try {
connection.getInputStream();
@@ -68,6 +69,7 @@ public final class TestUtils {
throws Exception {
URL url = new URL("https://" + host + ":" + port);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
+ connection.setInstanceFollowRedirects(false);
connection.setSSLSocketFactory(context.getSocketFactory());
connection.getInputStream();
}
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
index 5db02e376f3d..c11b6bb3435d 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
@@ -284,8 +284,11 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase {
// Stop the monitor
mIpSecPacketLossDetector.close();
+ mIpSecPacketLossDetector.close();
verifyStopped();
- verify(mIpSecTransform).close();
+
+ verify(mIpSecTransform, never()).close();
+ verify(mContext).unregisterReceiver(any());
}
@Test
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index a5962292b5b0..82ad9fa05145 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -2778,7 +2778,7 @@ bool ManifestExtractor::Extract(android::IDiagnostics* diag) {
auto file_path = it->Next()->GetSource().path.c_str();
const char* last_slash =
- android::util::ValidLibraryPathLastSlash(file_path, has_renderscript_bitcode, false);
+ android::util::ValidLibraryPathLastSlash(file_path, has_renderscript_bitcode);
if (last_slash) {
architectures_from_apk.insert(std::string(file_path + APK_LIB_LEN, last_slash));
}