summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--OWNERS1
-rw-r--r--SDK_OWNERS6
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java36
-rw-r--r--boot/boot-image-profile-extra.txt1
-rw-r--r--core/api/current.txt112
-rw-r--r--core/api/system-current.txt16
-rw-r--r--core/java/android/app/PropertyInvalidatedCache.java12
-rw-r--r--core/java/android/app/WallpaperManager.java34
-rw-r--r--core/java/android/app/admin/flags/flags.aconfig8
-rw-r--r--core/java/android/app/appfunctions/AppFunctionManager.java87
-rw-r--r--core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java141
-rw-r--r--core/java/android/app/performance.aconfig4
-rw-r--r--core/java/android/appwidget/AppWidgetHost.java45
-rw-r--r--core/java/android/content/Context.java2
-rw-r--r--core/java/android/content/Intent.java2
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java40
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java16
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java60
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java60
-rw-r--r--core/java/android/os/CombinedMessageQueue/MessageQueue.java72
-rw-r--r--core/java/android/os/UserManager.java50
-rw-r--r--core/java/android/os/VibrationEffect.java36
-rw-r--r--core/java/android/os/vibrator/PwlePoint.java66
-rw-r--r--core/java/android/permission/flags.aconfig18
-rw-r--r--core/java/android/security/advancedprotection/AdvancedProtectionFeature.aidl23
-rw-r--r--core/java/android/security/advancedprotection/AdvancedProtectionFeature.java77
-rw-r--r--core/java/android/security/advancedprotection/AdvancedProtectionManager.java19
-rw-r--r--core/java/android/security/advancedprotection/IAdvancedProtectionService.aidl3
-rw-r--r--core/java/android/security/responsible_apis_flags.aconfig8
-rw-r--r--core/java/android/service/contextualsearch/OWNERS3
-rw-r--r--core/java/android/telephony/TelephonyRegistryManager.java109
-rw-r--r--core/java/android/view/View.java94
-rw-r--r--core/java/android/view/accessibility/AccessibilityEvent.java24
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java65
-rw-r--r--core/java/android/view/accessibility/flags/accessibility_flags.aconfig7
-rw-r--r--core/java/android/window/WindowContainerTransaction.java26
-rw-r--r--core/java/com/android/internal/telephony/ISatelliteStateChangeListener.aidl21
-rw-r--r--core/java/com/android/internal/telephony/ITelephonyRegistry.aidl5
-rw-r--r--core/res/res/values-en-rCA/strings.xml15
-rw-r--r--core/res/res/values-it/strings.xml15
-rw-r--r--core/res/res/values-ne/strings.xml2
-rw-r--r--core/res/res/values-pt-rPT/strings.xml15
-rw-r--r--core/res/res/values-te/strings.xml2
-rw-r--r--core/res/res/values/attrs.xml6
-rw-r--r--core/res/res/values/public-staging.xml2
-rw-r--r--core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java2
-rw-r--r--core/tests/vibrator/src/android/os/VibrationEffectTest.java68
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedImageDrawable.java34
-rw-r--r--libs/WindowManager/Shell/res/values-ar/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-as/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-bn/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-bs/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-cs/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-el/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-en-rAU/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-en-rGB/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-en-rIN/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-hi/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-hr/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-is/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-it/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-ja/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-ka/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-km/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-kn/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-lt/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-mr/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-ms/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-ne/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-pl/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-pt-rPT/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-sl/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-ta/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-te/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-th/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-tl/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rCN/strings.xml6
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/pip/PipContentOverlay.java39
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java44
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java30
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java73
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java52
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt64
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java79
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java104
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java89
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java37
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java55
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModel.kt26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java12
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt163
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt12
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipResizeAnimatorTest.java276
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java8
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModelTest.kt27
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt30
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt2
-rw-r--r--libs/appfunctions/api/current.txt23
-rw-r--r--libs/appfunctions/java/com/google/android/appfunctions/sidecar/AppFunctionManager.java27
-rw-r--r--libs/appfunctions/java/com/google/android/appfunctions/sidecar/ExecuteAppFunctionResponse.java141
-rw-r--r--libs/appfunctions/tests/src/com/google/android/appfunctions/sidecar/tests/SidecarConverterTest.kt8
-rw-r--r--libs/hwui/aconfig/hwui_flags.aconfig8
-rw-r--r--libs/hwui/hwui/AnimatedImageDrawable.cpp22
-rw-r--r--libs/hwui/hwui/AnimatedImageDrawable.h5
-rw-r--r--libs/hwui/jni/AnimatedImageDrawable.cpp14
-rw-r--r--media/java/android/media/AudioAttributes.java36
-rw-r--r--media/java/android/media/AudioDeviceInfo.java33
-rw-r--r--media/java/android/media/AudioManager.java5
-rw-r--r--media/java/android/media/AudioSystem.java7
-rw-r--r--media/java/android/media/MediaCodecInfo.java260
-rw-r--r--media/java/android/media/MediaFormat.java3
-rw-r--r--media/java/android/media/MediaRecorder.java4
-rw-r--r--nfc/java/android/nfc/flags.aconfig8
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-in/arrays.xml4
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ky/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-or/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingId.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt42
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepositoryTest.kt35
-rw-r--r--packages/Shell/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/AndroidManifest.xml4
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig7
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationScrimNestedScrollConnection.kt8
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackNestedScrollConnection.kt64
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt6
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt3
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt1
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/Seek.kt23
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt18
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt35
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt10
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt41
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryLocalImplTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt)8
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/shared/model/CommunalWidgetContentModelTest.kt81
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/widgets/CommunalAppWidgetHostTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt55
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt63
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceTest.kt319
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetConfigurationControllerTest.kt10
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepositoryTest.kt114
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/CommandQueueInitializerTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationScrimNestedScrollConnectionTest.kt10
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt9
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java7
-rw-r--r--packages/SystemUI/res/values-af/strings.xml8
-rw-r--r--packages/SystemUI/res/values-am/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml8
-rw-r--r--packages/SystemUI/res/values-as/strings.xml14
-rw-r--r--packages/SystemUI/res/values-az/strings.xml8
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml14
-rw-r--r--packages/SystemUI/res/values-be/strings.xml8
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml8
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml14
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml14
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml8
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml8
-rw-r--r--packages/SystemUI/res/values-da/strings.xml14
-rw-r--r--packages/SystemUI/res/values-de/strings.xml8
-rw-r--r--packages/SystemUI/res/values-el/strings.xml8
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml8
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml23
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml8
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml8
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml14
-rw-r--r--packages/SystemUI/res/values-es/strings.xml8
-rw-r--r--packages/SystemUI/res/values-et/strings.xml8
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml8
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml14
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml8
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml8
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml8
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml8
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml14
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml8
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml8
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml8
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml8
-rw-r--r--packages/SystemUI/res/values-in/strings.xml12
-rw-r--r--packages/SystemUI/res/values-is/strings.xml14
-rw-r--r--packages/SystemUI/res/values-it/strings.xml23
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml14
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml8
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml8
-rw-r--r--packages/SystemUI/res/values-km/strings.xml8
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml14
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml16
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml8
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml8
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml8
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml8
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml14
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml14
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml14
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml14
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml8
-rw-r--r--packages/SystemUI/res/values-my/strings.xml8
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml8
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml14
-rw-r--r--packages/SystemUI/res/values-or/strings.xml8
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml14
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml8
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml8
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml23
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml14
-rw-r--r--packages/SystemUI/res/values-si/strings.xml8
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml14
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml8
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml8
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml14
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml8
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml8
-rw-r--r--packages/SystemUI/res/values-sw600dp/dimens.xml8
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml8
-rw-r--r--packages/SystemUI/res/values-te/strings.xml14
-rw-r--r--packages/SystemUI/res/values-th/strings.xml8
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml8
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml8
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml10
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml8
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml8
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml14
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml8
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml8
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml8
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml8
-rw-r--r--packages/SystemUI/res/values/dimens.xml6
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/dagger/GlanceableHubWidgetManagerModule.kt38
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryModule.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryRemoteImpl.kt85
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalWidgetContentModel.aidl19
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalWidgetContentModel.kt101
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/shared/model/GlanceableHubMultiUserHelper.kt74
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHost.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartable.kt99
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManager.kt171
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerService.kt305
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceInfo.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceSupplier.kt74
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/IGlanceableHubWidgetManagerService.aidl51
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/ServiceWatcherFactory.kt55
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetConfigurationController.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt38
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCommand.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutKey.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/core/CommandQueueInitializer.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt61
-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/wmshell/BubblesTest.java36
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt47
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/communal/shared/model/FakeGlanceableHubMultiUserHelper.kt48
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/communal/shared/model/GlanceableHubMultiUserHelperKosmos.kt24
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerKosmos.kt22
-rw-r--r--packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java9
-rw-r--r--packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java17
-rw-r--r--services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java20
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java25
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java131
-rw-r--r--services/core/java/com/android/server/am/OWNERS1
-rw-r--r--services/core/java/com/android/server/am/broadcasts_flags.aconfig10
-rw-r--r--services/core/java/com/android/server/am/flags.aconfig8
-rw-r--r--services/core/java/com/android/server/audio/MediaFocusControl.java1
-rw-r--r--services/core/java/com/android/server/input/InputGestureManager.java24
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java1
-rw-r--r--services/core/java/com/android/server/input/KeyGestureController.java199
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java24
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java42
-rw-r--r--services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java36
-rw-r--r--services/core/java/com/android/server/security/advancedprotection/features/AdvancedProtectionHook.java4
-rw-r--r--services/core/java/com/android/server/security/advancedprotection/features/AdvancedProtectionProvider.java27
-rw-r--r--services/core/java/com/android/server/vibrator/ComposePwleV2VibratorStep.java37
-rw-r--r--services/core/java/com/android/server/vibrator/VibrationStats.java16
-rw-r--r--services/core/java/com/android/server/vibrator/VibratorController.java16
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperDataParser.java8
-rw-r--r--services/core/java/com/android/server/webkit/WebViewUpdateService.java7
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecordInputSink.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartController.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java43
-rw-r--r--services/core/java/com/android/server/wm/BackgroundActivityStartController.java10
-rw-r--r--services/core/java/com/android/server/wm/Task.java6
-rw-r--r--services/core/java/com/android/server/wm/Transition.java66
-rw-r--r--services/core/java/com/android/server/wm/TransparentPolicy.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java4
-rw-r--r--services/core/java/com/android/server/wm/utils/RegionUtils.java5
-rw-r--r--services/core/jni/com_android_server_vibrator_VibratorController.cpp29
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperCropperTest.java19
-rw-r--r--services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java96
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java38
-rw-r--r--services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java65
-rw-r--r--services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerTest.java8
-rw-r--r--services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorControllerProvider.java37
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TransparentPolicyTest.java14
-rw-r--r--telephony/java/android/telephony/satellite/SatelliteManager.java77
-rw-r--r--telephony/java/android/telephony/satellite/SatelliteStateChangeListener.java51
-rw-r--r--tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt66
-rw-r--r--tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt4
-rw-r--r--tools/protologtool/src/com/android/protolog/tool/ViewerConfigJsonBuilder.kt3
-rw-r--r--tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt8
-rw-r--r--tools/protologtool/tests/com/android/protolog/tool/ViewerConfigJsonBuilderTest.kt6
-rw-r--r--tools/protologtool/tests/com/android/protolog/tool/ViewerConfigProtoBuilderTest.kt68
351 files changed, 7363 insertions, 1295 deletions
diff --git a/OWNERS b/OWNERS
index eb2bfcfdf82d..d0a634e529c5 100644
--- a/OWNERS
+++ b/OWNERS
@@ -47,3 +47,4 @@ per-file MULTIUSER_OWNERS = file:/MULTIUSER_OWNERS
per-file BROADCASTS_OWNERS = file:/BROADCASTS_OWNERS
per-file ADPF_OWNERS = file:/ADPF_OWNERS
per-file GAME_MANAGER_OWNERS = file:/GAME_MANAGER_OWNERS
+per-file SDK_OWNERS = file:/SDK_OWNERS
diff --git a/SDK_OWNERS b/SDK_OWNERS
new file mode 100644
index 000000000000..c9ca47aa4703
--- /dev/null
+++ b/SDK_OWNERS
@@ -0,0 +1,6 @@
+amhk@google.com
+kimalexander@google.com
+lus@google.com
+michaelwr@google.com
+nanaasiedu@google.com
+paulduffin@google.com
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index ff4af69fd77c..8bd3ef4f4d1a 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -121,6 +121,9 @@ public final class QuotaController extends StateController {
private static final String ALARM_TAG_CLEANUP = "*job.cleanup*";
private static final String ALARM_TAG_QUOTA_CHECK = "*job.quota_check*";
+ private static final String TRACE_QUOTA_STATE_CHANGED_TAG = "QuotaStateChanged:";
+ private static final String TRACE_QUOTA_STATE_CHANGED_DELIMITER = "#";
+
private static final int SYSTEM_APP_CHECK_FLAGS =
PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| PackageManager.GET_PERMISSIONS | PackageManager.MATCH_KNOWN_PACKAGES;
@@ -2657,11 +2660,12 @@ public final class QuotaController extends StateController {
if (timeRemainingMs <= 50) {
// Less than 50 milliseconds left. Start process of shutting down jobs.
if (DEBUG) Slog.d(TAG, pkg + " has reached its quota.");
- if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
- Trace.instantForTrack(Trace.TRACE_TAG_SYSTEM_SERVER,
- JobSchedulerService.TRACE_TRACK_NAME,
- pkg + "#" + MSG_REACHED_TIME_QUOTA);
- }
+ final StringBuilder traceMsg = new StringBuilder();
+ traceMsg.append(TRACE_QUOTA_STATE_CHANGED_TAG)
+ .append(pkg)
+ .append(TRACE_QUOTA_STATE_CHANGED_DELIMITER)
+ .append(MSG_REACHED_TIME_QUOTA);
+ Trace.instant(Trace.TRACE_TAG_POWER, traceMsg.toString());
mStateChangedListener.onControllerStateChanged(
maybeUpdateConstraintForPkgLocked(
sElapsedRealtimeClock.millis(),
@@ -2690,11 +2694,12 @@ public final class QuotaController extends StateController {
pkg.userId, pkg.packageName);
if (timeRemainingMs <= 0) {
if (DEBUG) Slog.d(TAG, pkg + " has reached its EJ quota.");
- if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
- Trace.instantForTrack(Trace.TRACE_TAG_SYSTEM_SERVER,
- JobSchedulerService.TRACE_TRACK_NAME,
- pkg + "#" + MSG_REACHED_EJ_TIME_QUOTA);
- }
+ final StringBuilder traceMsg = new StringBuilder();
+ traceMsg.append(TRACE_QUOTA_STATE_CHANGED_TAG)
+ .append(pkg)
+ .append(TRACE_QUOTA_STATE_CHANGED_DELIMITER)
+ .append(MSG_REACHED_EJ_TIME_QUOTA);
+ Trace.instant(Trace.TRACE_TAG_POWER, traceMsg.toString());
mStateChangedListener.onControllerStateChanged(
maybeUpdateConstraintForPkgLocked(
sElapsedRealtimeClock.millis(),
@@ -2719,11 +2724,12 @@ public final class QuotaController extends StateController {
Slog.d(TAG, pkg + " has reached its count quota.");
}
- if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
- Trace.instantForTrack(Trace.TRACE_TAG_SYSTEM_SERVER,
- JobSchedulerService.TRACE_TRACK_NAME,
- pkg + "#" + MSG_REACHED_COUNT_QUOTA);
- }
+ final StringBuilder traceMsg = new StringBuilder();
+ traceMsg.append(TRACE_QUOTA_STATE_CHANGED_TAG)
+ .append(pkg)
+ .append(TRACE_QUOTA_STATE_CHANGED_DELIMITER)
+ .append(MSG_REACHED_COUNT_QUOTA);
+ Trace.instant(Trace.TRACE_TAG_POWER, traceMsg.toString());
mStateChangedListener.onControllerStateChanged(
maybeUpdateConstraintForPkgLocked(
diff --git a/boot/boot-image-profile-extra.txt b/boot/boot-image-profile-extra.txt
index 11ca1dcc181e..e31eb3a993f0 100644
--- a/boot/boot-image-profile-extra.txt
+++ b/boot/boot-image-profile-extra.txt
@@ -23,3 +23,4 @@ HSPLandroid/graphics/Color;->luminance()F
# For now, compile all methods in MessageQueue to avoid performance cliffs for
# flagged/evolving hot code paths. See: b/338098106
HSPLandroid/os/MessageQueue;->*
+HSPLandroid/os/MessageQueue$*;->*
diff --git a/core/api/current.txt b/core/api/current.txt
index 0212fe3a58b3..fd2402a7a70d 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1609,6 +1609,7 @@ package android {
field public static final int summaryColumn = 16843426; // 0x10102a2
field public static final int summaryOff = 16843248; // 0x10101f0
field public static final int summaryOn = 16843247; // 0x10101ef
+ field @FlaggedApi("android.view.accessibility.supplemental_description") public static final int supplementalDescription;
field public static final int supportedTypes = 16844369; // 0x1010651
field public static final int supportsAssist = 16844016; // 0x10104f0
field public static final int supportsBatteryGameMode = 16844374; // 0x1010656
@@ -8783,7 +8784,8 @@ package android.app.appfunctions {
@FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public final class AppFunctionManager {
method @RequiresPermission(anyOf={"android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED", "android.permission.EXECUTE_APP_FUNCTIONS"}, conditional=true) public void executeAppFunction(@NonNull android.app.appfunctions.ExecuteAppFunctionRequest, @NonNull java.util.concurrent.Executor, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.app.appfunctions.ExecuteAppFunctionResponse>);
- method public void isAppFunctionEnabled(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,java.lang.Exception>);
+ method @RequiresPermission(anyOf={"android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED", "android.permission.EXECUTE_APP_FUNCTIONS"}, conditional=true) public void isAppFunctionEnabled(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,java.lang.Exception>);
+ method public void isAppFunctionEnabled(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,java.lang.Exception>);
method public void setAppFunctionEnabled(@NonNull String, int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,java.lang.Exception>);
field public static final int APP_FUNCTION_STATE_DEFAULT = 0; // 0x0
field public static final int APP_FUNCTION_STATE_DISABLED = 2; // 0x2
@@ -8816,6 +8818,7 @@ package android.app.appfunctions {
@FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public final class ExecuteAppFunctionResponse implements android.os.Parcelable {
method public int describeContents();
+ method public int getErrorCategory();
method @Nullable public String getErrorMessage();
method @NonNull public android.os.Bundle getExtras();
method public int getResultCode();
@@ -8825,14 +8828,19 @@ package android.app.appfunctions {
method @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") @NonNull public static android.app.appfunctions.ExecuteAppFunctionResponse newSuccess(@NonNull android.app.appsearch.GenericDocument, @Nullable android.os.Bundle);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.appfunctions.ExecuteAppFunctionResponse> CREATOR;
+ field public static final int ERROR_CATEGORY_APP = 3; // 0x3
+ field public static final int ERROR_CATEGORY_REQUEST_ERROR = 1; // 0x1
+ field public static final int ERROR_CATEGORY_SYSTEM = 2; // 0x2
+ field public static final int ERROR_CATEGORY_UNKNOWN = 0; // 0x0
field public static final String PROPERTY_RETURN_VALUE = "returnValue";
- field public static final int RESULT_APP_UNKNOWN_ERROR = 2; // 0x2
- field public static final int RESULT_CANCELLED = 6; // 0x6
- field public static final int RESULT_DENIED = 1; // 0x1
- field public static final int RESULT_DISABLED = 5; // 0x5
- field public static final int RESULT_INTERNAL_ERROR = 3; // 0x3
- field public static final int RESULT_INVALID_ARGUMENT = 4; // 0x4
+ field public static final int RESULT_APP_UNKNOWN_ERROR = 3000; // 0xbb8
+ field public static final int RESULT_CANCELLED = 2001; // 0x7d1
+ field public static final int RESULT_DENIED = 1000; // 0x3e8
+ field public static final int RESULT_DISABLED = 1002; // 0x3ea
+ field public static final int RESULT_FUNCTION_NOT_FOUND = 1003; // 0x3eb
+ field public static final int RESULT_INVALID_ARGUMENT = 1001; // 0x3e9
field public static final int RESULT_OK = 0; // 0x0
+ field public static final int RESULT_SYSTEM_ERROR = 2000; // 0x7d0
}
}
@@ -10941,6 +10949,7 @@ package android.content {
field public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 1; // 0x1
field public static final String RESTRICTIONS_SERVICE = "restrictions";
field public static final String ROLE_SERVICE = "role";
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_state_change_listener") public static final String SATELLITE_SERVICE = "satellite";
field public static final String SEARCH_SERVICE = "search";
field @FlaggedApi("android.os.security_state_service") public static final String SECURITY_STATE_SERVICE = "security_state";
field public static final String SENSOR_SERVICE = "sensor";
@@ -19333,6 +19342,8 @@ package android.hardware.camera2 {
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> AUTOMOTIVE_LENS_FACING;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> AUTOMOTIVE_LOCATION;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
+ field @FlaggedApi("com.android.internal.camera.flags.color_temperature") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_MODES;
+ field @FlaggedApi("com.android.internal.camera.flags.color_temperature") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Integer>> COLOR_CORRECTION_COLOR_TEMPERATURE_RANGE;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AE_AVAILABLE_MODES;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Integer>[]> CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
@@ -19634,6 +19645,7 @@ package android.hardware.camera2 {
field public static final int COLOR_CORRECTION_ABERRATION_MODE_FAST = 1; // 0x1
field public static final int COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY = 2; // 0x2
field public static final int COLOR_CORRECTION_ABERRATION_MODE_OFF = 0; // 0x0
+ field @FlaggedApi("com.android.internal.camera.flags.color_temperature") public static final int COLOR_CORRECTION_MODE_CCT = 3; // 0x3
field public static final int COLOR_CORRECTION_MODE_FAST = 1; // 0x1
field public static final int COLOR_CORRECTION_MODE_HIGH_QUALITY = 2; // 0x2
field public static final int COLOR_CORRECTION_MODE_TRANSFORM_MATRIX = 0; // 0x0
@@ -19920,6 +19932,8 @@ package android.hardware.camera2 {
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> BLACK_LEVEL_LOCK;
field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> COLOR_CORRECTION_ABERRATION_MODE;
+ field @FlaggedApi("com.android.internal.camera.flags.color_temperature") @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> COLOR_CORRECTION_COLOR_TEMPERATURE;
+ field @FlaggedApi("com.android.internal.camera.flags.color_temperature") @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> COLOR_CORRECTION_COLOR_TINT;
field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<android.hardware.camera2.params.RggbChannelVector> COLOR_CORRECTION_GAINS;
field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> COLOR_CORRECTION_MODE;
field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<android.hardware.camera2.params.ColorSpaceTransform> COLOR_CORRECTION_TRANSFORM;
@@ -20010,6 +20024,8 @@ package android.hardware.camera2 {
method public int getSequenceId();
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Boolean> BLACK_LEVEL_LOCK;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> COLOR_CORRECTION_ABERRATION_MODE;
+ field @FlaggedApi("com.android.internal.camera.flags.color_temperature") @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> COLOR_CORRECTION_COLOR_TEMPERATURE;
+ field @FlaggedApi("com.android.internal.camera.flags.color_temperature") @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> COLOR_CORRECTION_COLOR_TINT;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.RggbChannelVector> COLOR_CORRECTION_GAINS;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> COLOR_CORRECTION_MODE;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.ColorSpaceTransform> COLOR_CORRECTION_TRANSFORM;
@@ -21391,6 +21407,7 @@ package android.media {
field public static final int TYPE_IP = 20; // 0x14
field public static final int TYPE_LINE_ANALOG = 5; // 0x5
field public static final int TYPE_LINE_DIGITAL = 6; // 0x6
+ field @FlaggedApi("android.media.audio.enable_multichannel_group_device") public static final int TYPE_MULTICHANNEL_GROUP = 32; // 0x20
field public static final int TYPE_REMOTE_SUBMIX = 25; // 0x19
field public static final int TYPE_TELEPHONY = 18; // 0x12
field public static final int TYPE_TV_TUNER = 17; // 0x11
@@ -23108,6 +23125,65 @@ package android.media {
field public static final int AC4Profile11 = 514; // 0x202
field public static final int AC4Profile21 = 1026; // 0x402
field public static final int AC4Profile22 = 1028; // 0x404
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel11Band0 = 513; // 0x201
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel11Band1 = 514; // 0x202
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel11Band2 = 516; // 0x204
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel11Band3 = 520; // 0x208
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel1Band0 = 257; // 0x101
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel1Band1 = 258; // 0x102
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel1Band2 = 260; // 0x104
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel1Band3 = 264; // 0x108
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel21Band0 = 2049; // 0x801
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel21Band1 = 2050; // 0x802
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel21Band2 = 2052; // 0x804
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel21Band3 = 2056; // 0x808
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel2Band0 = 1025; // 0x401
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel2Band1 = 1026; // 0x402
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel2Band2 = 1028; // 0x404
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel2Band3 = 1032; // 0x408
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel31Band0 = 8193; // 0x2001
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel31Band1 = 8194; // 0x2002
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel31Band2 = 8196; // 0x2004
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel31Band3 = 8200; // 0x2008
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel3Band0 = 4097; // 0x1001
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel3Band1 = 4098; // 0x1002
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel3Band2 = 4100; // 0x1004
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel3Band3 = 4104; // 0x1008
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel41Band0 = 32769; // 0x8001
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel41Band1 = 32770; // 0x8002
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel41Band2 = 32772; // 0x8004
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel41Band3 = 32776; // 0x8008
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel4Band0 = 16385; // 0x4001
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel4Band1 = 16386; // 0x4002
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel4Band2 = 16388; // 0x4004
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel4Band3 = 16392; // 0x4008
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel51Band0 = 131073; // 0x20001
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel51Band1 = 131074; // 0x20002
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel51Band2 = 131076; // 0x20004
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel51Band3 = 131080; // 0x20008
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel5Band0 = 65537; // 0x10001
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel5Band1 = 65538; // 0x10002
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel5Band2 = 65540; // 0x10004
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel5Band3 = 65544; // 0x10008
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel61Band0 = 524289; // 0x80001
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel61Band1 = 524290; // 0x80002
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel61Band2 = 524292; // 0x80004
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel61Band3 = 524296; // 0x80008
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel6Band0 = 262145; // 0x40001
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel6Band1 = 262146; // 0x40002
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel6Band2 = 262148; // 0x40004
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel6Band3 = 262152; // 0x40008
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel71Band0 = 2097153; // 0x200001
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel71Band1 = 2097154; // 0x200002
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel71Band2 = 2097156; // 0x200004
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel71Band3 = 2097160; // 0x200008
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel7Band0 = 1048577; // 0x100001
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel7Band1 = 1048578; // 0x100002
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel7Band2 = 1048580; // 0x100004
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel7Band3 = 1048584; // 0x100008
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVProfile422_10 = 1; // 0x1
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVProfile422_10HDR10 = 4096; // 0x1000
+ field @FlaggedApi("android.media.codec.apv_support") public static final int APVProfile422_10HDR10Plus = 8192; // 0x2000
field public static final int AV1Level2 = 1; // 0x1
field public static final int AV1Level21 = 2; // 0x2
field public static final int AV1Level22 = 4; // 0x4
@@ -23958,6 +24034,7 @@ package android.media {
field public static final String MIMETYPE_TEXT_CEA_708 = "text/cea-708";
field public static final String MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
field public static final String MIMETYPE_TEXT_VTT = "text/vtt";
+ field @FlaggedApi("android.media.codec.apv_support") public static final String MIMETYPE_VIDEO_APV = "video/apv";
field public static final String MIMETYPE_VIDEO_AV1 = "video/av01";
field public static final String MIMETYPE_VIDEO_AVC = "video/avc";
field public static final String MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
@@ -34454,6 +34531,7 @@ package android.os {
method public int describeContents();
method @NonNull public static android.os.VibrationEffect.Composition startComposition();
method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public static android.os.VibrationEffect.WaveformEnvelopeBuilder startWaveformEnvelope();
+ method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public static android.os.VibrationEffect.WaveformEnvelopeBuilder startWaveformEnvelope(@FloatRange(from=0) float);
field @NonNull public static final android.os.Parcelable.Creator<android.os.VibrationEffect> CREATOR;
field public static final int DEFAULT_AMPLITUDE = -1; // 0xffffffff
field public static final int EFFECT_CLICK = 0; // 0x0
@@ -39834,7 +39912,7 @@ package android.security {
package android.security.advancedprotection {
- @FlaggedApi("android.security.aapm_api") public class AdvancedProtectionManager {
+ @FlaggedApi("android.security.aapm_api") public final class AdvancedProtectionManager {
method @RequiresPermission(android.Manifest.permission.QUERY_ADVANCED_PROTECTION_MODE) public boolean isAdvancedProtectionEnabled();
method @RequiresPermission(android.Manifest.permission.QUERY_ADVANCED_PROTECTION_MODE) public void registerAdvancedProtectionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.security.advancedprotection.AdvancedProtectionManager.Callback);
method @RequiresPermission(android.Manifest.permission.QUERY_ADVANCED_PROTECTION_MODE) public void unregisterAdvancedProtectionCallback(@NonNull android.security.advancedprotection.AdvancedProtectionManager.Callback);
@@ -47790,6 +47868,19 @@ package android.telephony.mbms {
}
+package android.telephony.satellite {
+
+ @FlaggedApi("com.android.internal.telephony.flags.satellite_state_change_listener") public final class SatelliteManager {
+ method @FlaggedApi("com.android.internal.telephony.flags.satellite_state_change_listener") @RequiresPermission(anyOf={android.Manifest.permission.READ_BASIC_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE, "carrier privileges"}) public void registerStateChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteStateChangeListener);
+ method @FlaggedApi("com.android.internal.telephony.flags.satellite_state_change_listener") @RequiresPermission(anyOf={android.Manifest.permission.READ_BASIC_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE, "carrier privileges"}) public void unregisterStateChangeListener(@NonNull android.telephony.satellite.SatelliteStateChangeListener);
+ }
+
+ @FlaggedApi("com.android.internal.telephony.flags.satellite_state_change_listener") public interface SatelliteStateChangeListener {
+ method public void onEnabledStateChanged(boolean);
+ }
+
+}
+
package android.text {
@Deprecated public class AlteredCharSequence implements java.lang.CharSequence android.text.GetChars {
@@ -53148,6 +53239,7 @@ package android.view {
method public android.animation.StateListAnimator getStateListAnimator();
method protected int getSuggestedMinimumHeight();
method protected int getSuggestedMinimumWidth();
+ method @FlaggedApi("android.view.accessibility.supplemental_description") @Nullable public CharSequence getSupplementalDescription();
method @NonNull public java.util.List<android.graphics.Rect> getSystemGestureExclusionRects();
method @Deprecated public int getSystemUiVisibility();
method public Object getTag();
@@ -53528,6 +53620,7 @@ package android.view {
method public void setSoundEffectsEnabled(boolean);
method public void setStateDescription(@Nullable CharSequence);
method public void setStateListAnimator(android.animation.StateListAnimator);
+ method @FlaggedApi("android.view.accessibility.supplemental_description") public void setSupplementalDescription(@Nullable CharSequence);
method public void setSystemGestureExclusionRects(@NonNull java.util.List<android.graphics.Rect>);
method @Deprecated public void setSystemUiVisibility(int);
method public void setTag(Object);
@@ -55134,6 +55227,7 @@ package android.view.accessibility {
field public static final int CONTENT_CHANGE_TYPE_PANE_TITLE = 8; // 0x8
field public static final int CONTENT_CHANGE_TYPE_STATE_DESCRIPTION = 64; // 0x40
field public static final int CONTENT_CHANGE_TYPE_SUBTREE = 1; // 0x1
+ field @FlaggedApi("android.view.accessibility.supplemental_description") public static final int CONTENT_CHANGE_TYPE_SUPPLEMENTAL_DESCRIPTION = 32768; // 0x8000
field public static final int CONTENT_CHANGE_TYPE_TEXT = 2; // 0x2
field public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0; // 0x0
field @NonNull public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityEvent> CREATOR;
@@ -55296,6 +55390,7 @@ package android.view.accessibility {
method @Nullable public android.view.accessibility.AccessibilityNodeInfo getParent(int);
method public android.view.accessibility.AccessibilityNodeInfo.RangeInfo getRangeInfo();
method @Nullable public CharSequence getStateDescription();
+ method @FlaggedApi("android.view.accessibility.supplemental_description") @Nullable public CharSequence getSupplementalDescription();
method public CharSequence getText();
method public int getTextSelectionEnd();
method public int getTextSelectionStart();
@@ -55404,6 +55499,7 @@ package android.view.accessibility {
method public void setSource(android.view.View);
method public void setSource(android.view.View, int);
method public void setStateDescription(@Nullable CharSequence);
+ method @FlaggedApi("android.view.accessibility.supplemental_description") public void setSupplementalDescription(@Nullable CharSequence);
method public void setText(CharSequence);
method public void setTextEntryKey(boolean);
method public void setTextSelectable(boolean);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 9879e7f18c67..e4d55896744c 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -7230,7 +7230,6 @@ package android.media {
field @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public static final int USAGE_CALL_ASSISTANT = 17; // 0x11
field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int USAGE_EMERGENCY = 1000; // 0x3e8
field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int USAGE_SAFETY = 1001; // 0x3e9
- field @FlaggedApi("android.media.audio.speaker_cleanup_usage") @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int USAGE_SPEAKER_CLEANUP = 1004; // 0x3ec
field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int USAGE_VEHICLE_STATUS = 1002; // 0x3ea
}
@@ -7605,7 +7604,7 @@ package android.media {
public final class MediaRecorder.AudioSource {
field @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT) public static final int ECHO_REFERENCE = 1997; // 0x7cd
field @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_HOTWORD) public static final int HOTWORD = 1999; // 0x7cf
- field @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT) public static final int RADIO_TUNER = 1998; // 0x7ce
+ field @RequiresPermission(android.Manifest.permission.CAPTURE_TUNER_AUDIO_INPUT) public static final int RADIO_TUNER = 1998; // 0x7ce
field @RequiresPermission(android.Manifest.permission.ACCESS_ULTRASOUND) public static final int ULTRASOUND = 2000; // 0x7d0
}
@@ -12467,7 +12466,16 @@ package android.security {
package android.security.advancedprotection {
- @FlaggedApi("android.security.aapm_api") public class AdvancedProtectionManager {
+ @FlaggedApi("android.security.aapm_api") public final class AdvancedProtectionFeature implements android.os.Parcelable {
+ ctor public AdvancedProtectionFeature(@NonNull String);
+ method public int describeContents();
+ method @NonNull public String getId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.security.advancedprotection.AdvancedProtectionFeature> CREATOR;
+ }
+
+ @FlaggedApi("android.security.aapm_api") public final class AdvancedProtectionManager {
+ method @NonNull @RequiresPermission(android.Manifest.permission.SET_ADVANCED_PROTECTION_MODE) public java.util.List<android.security.advancedprotection.AdvancedProtectionFeature> getAdvancedProtectionFeatures();
method @RequiresPermission(android.Manifest.permission.SET_ADVANCED_PROTECTION_MODE) public void setAdvancedProtectionEnabled(boolean);
}
@@ -18245,7 +18253,7 @@ package android.telephony.satellite {
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void onSatelliteDatagramReceived(long, @NonNull android.telephony.satellite.SatelliteDatagram, int, @NonNull java.util.function.Consumer<java.lang.Void>);
}
- public final class SatelliteManager {
+ @FlaggedApi("com.android.internal.telephony.flags.satellite_state_change_listener") public final class SatelliteManager {
method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void addAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void deprovisionService(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.Set<java.lang.Integer> getAttachRestrictionReasonsForCarrier(int);
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 26bfec348a6f..a39cf84a4ebe 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -811,10 +811,20 @@ public class PropertyInvalidatedCache<Query, Result> {
return false; // Always disable shared memory on Ravenwood. (for now)
}
+ /**
+ * Keys that cannot be put in shared memory yet.
+ */
+ private static boolean inSharedMemoryDenyList(@NonNull String name) {
+ final String pkginfo = PREFIX_SYSTEM + "package_info";
+ return name.equals(pkginfo);
+ };
+
// Return true if this cache can use shared memory for its nonce. Shared memory may be used
// if the module is the system.
private static boolean sharedMemoryOkay(@NonNull String name) {
- return sSharedMemoryAvailable && name.startsWith(PREFIX_SYSTEM);
+ return sSharedMemoryAvailable
+ && name.startsWith(PREFIX_SYSTEM)
+ && !inSharedMemoryDenyList(name);
}
/**
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 014e4660f944..60cc67707b2f 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -319,12 +319,12 @@ public class WallpaperManager {
* This is only used internally by the framework and the WallpaperBackupAgent.
* @hide
*/
- @IntDef(value = {
+ @IntDef(prefix = { "ORIENTATION_" }, value = {
ORIENTATION_UNKNOWN,
- PORTRAIT,
- LANDSCAPE,
- SQUARE_PORTRAIT,
- SQUARE_LANDSCAPE,
+ ORIENTATION_PORTRAIT,
+ ORIENTATION_LANDSCAPE,
+ ORIENTATION_SQUARE_PORTRAIT,
+ ORIENTATION_SQUARE_LANDSCAPE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ScreenOrientation {}
@@ -338,25 +338,25 @@ public class WallpaperManager {
* Portrait orientation of most screens
* @hide
*/
- public static final int PORTRAIT = 0;
+ public static final int ORIENTATION_PORTRAIT = 0;
/**
* Landscape orientation of most screens
* @hide
*/
- public static final int LANDSCAPE = 1;
+ public static final int ORIENTATION_LANDSCAPE = 1;
/**
* Portrait orientation with similar width and height (e.g. the inner screen of a foldable)
* @hide
*/
- public static final int SQUARE_PORTRAIT = 2;
+ public static final int ORIENTATION_SQUARE_PORTRAIT = 2;
/**
* Landscape orientation with similar width and height (e.g. the inner screen of a foldable)
* @hide
*/
- public static final int SQUARE_LANDSCAPE = 3;
+ public static final int ORIENTATION_SQUARE_LANDSCAPE = 3;
/**
* Converts a (width, height) screen size to a {@link ScreenOrientation}.
@@ -367,10 +367,10 @@ public class WallpaperManager {
public static @ScreenOrientation int getOrientation(Point screenSize) {
float ratio = ((float) screenSize.x) / screenSize.y;
// ratios between 3/4 and 4/3 are considered square
- return ratio >= 4 / 3f ? LANDSCAPE
- : ratio > 1f ? SQUARE_LANDSCAPE
- : ratio > 3 / 4f ? SQUARE_PORTRAIT
- : PORTRAIT;
+ return ratio >= 4 / 3f ? ORIENTATION_LANDSCAPE
+ : ratio > 1f ? ORIENTATION_SQUARE_LANDSCAPE
+ : ratio > 3 / 4f ? ORIENTATION_SQUARE_PORTRAIT
+ : ORIENTATION_PORTRAIT;
}
/**
@@ -379,10 +379,10 @@ public class WallpaperManager {
*/
public static @ScreenOrientation int getRotatedOrientation(@ScreenOrientation int orientation) {
switch (orientation) {
- case PORTRAIT: return LANDSCAPE;
- case LANDSCAPE: return PORTRAIT;
- case SQUARE_PORTRAIT: return SQUARE_LANDSCAPE;
- case SQUARE_LANDSCAPE: return SQUARE_PORTRAIT;
+ case ORIENTATION_PORTRAIT: return ORIENTATION_LANDSCAPE;
+ case ORIENTATION_LANDSCAPE: return ORIENTATION_PORTRAIT;
+ case ORIENTATION_SQUARE_PORTRAIT: return ORIENTATION_SQUARE_LANDSCAPE;
+ case ORIENTATION_SQUARE_LANDSCAPE: return ORIENTATION_SQUARE_PORTRAIT;
default: return ORIENTATION_UNKNOWN;
}
}
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index fd583773d4e9..3aaca25eca15 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -341,3 +341,11 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "set_mte_policy_coexistence"
+ is_exported: true
+ namespace: "enterprise"
+ description: "Enables coexistence support for Setting MTE policy."
+ bug: "376213673"
+}
diff --git a/core/java/android/app/appfunctions/AppFunctionManager.java b/core/java/android/app/appfunctions/AppFunctionManager.java
index 74cae07d8911..5ddb590add4c 100644
--- a/core/java/android/app/appfunctions/AppFunctionManager.java
+++ b/core/java/android/app/appfunctions/AppFunctionManager.java
@@ -53,8 +53,8 @@ import java.util.function.Consumer;
* offers a more convenient and type-safe way to build app functions. The SDK provides predefined
* function schemas for common use cases and associated data classes for function parameters and
* return values. Apps only have to implement the provided interfaces. Internally, the SDK converts
- * these data classes into {@link ExecuteAppFunctionRequest#getParameters()} and
- * {@link ExecuteAppFunctionResponse#getResultDocument()}.
+ * these data classes into {@link ExecuteAppFunctionRequest#getParameters()} and {@link
+ * ExecuteAppFunctionResponse#getResultDocument()}.
*
* <p>**Discovering App Functions:**
*
@@ -69,13 +69,12 @@ import java.util.function.Consumer;
* <p>**Executing App Functions:**
*
* <p>To execute an app function, the caller app can retrieve the {@code functionIdentifier} from
- * the {@code AppFunctionStaticMetadata} document and use it to build an
- * {@link ExecuteAppFunctionRequest}. Then, invoke {@link #executeAppFunction} with the request
- * to execute the app function. Callers need the {@code android.permission.EXECUTE_APP_FUNCTIONS}
- * or {@code android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} permission to execute app
- * functions from other apps. An app can always execute its own app functions and doesn't need these
- * permissions. AppFunction SDK provides a convenient way to achieve this and is the preferred
- * method.
+ * the {@code AppFunctionStaticMetadata} document and use it to build an {@link
+ * ExecuteAppFunctionRequest}. Then, invoke {@link #executeAppFunction} with the request to execute
+ * the app function. Callers need the {@code android.permission.EXECUTE_APP_FUNCTIONS} or {@code
+ * android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} permission to execute app functions from other
+ * apps. An app can always execute its own app functions and doesn't need these permissions.
+ * AppFunction SDK provides a convenient way to achieve this and is the preferred method.
*
* <p>**Example:**
*
@@ -213,12 +212,13 @@ public final class AppFunctionManager {
/**
* Returns a boolean through a callback, indicating whether the app function is enabled.
*
- * <p>* This method can only check app functions owned by the caller, or those where the caller
+ * <p>This method can only check app functions owned by the caller, or those where the caller
* has visibility to the owner package and holds either the {@link
* Manifest.permission#EXECUTE_APP_FUNCTIONS} or {@link
* Manifest.permission#EXECUTE_APP_FUNCTIONS_TRUSTED} permission.
*
- * <p>If operation fails, the callback's {@link OutcomeReceiver#onError} is called with errors:
+ * <p>If the operation fails, the callback's {@link OutcomeReceiver#onError} is called with
+ * errors:
*
* <ul>
* <li>{@link IllegalArgumentException}, if the function is not found or the caller does not
@@ -232,23 +232,47 @@ public final class AppFunctionManager {
* @param executor the executor to run the request
* @param callback the callback to receive the function enabled check result
*/
+ @RequiresPermission(
+ anyOf = {
+ Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED,
+ Manifest.permission.EXECUTE_APP_FUNCTIONS
+ },
+ conditional = true)
public void isAppFunctionEnabled(
@NonNull String functionIdentifier,
@NonNull String targetPackage,
@NonNull Executor executor,
@NonNull OutcomeReceiver<Boolean, Exception> callback) {
- Objects.requireNonNull(functionIdentifier);
- Objects.requireNonNull(targetPackage);
- Objects.requireNonNull(executor);
- Objects.requireNonNull(callback);
- AppSearchManager appSearchManager = mContext.getSystemService(AppSearchManager.class);
- if (appSearchManager == null) {
- callback.onError(new IllegalStateException("Failed to get AppSearchManager."));
- return;
- }
+ isAppFunctionEnabledInternal(functionIdentifier, targetPackage, executor, callback);
+ }
- AppFunctionManagerHelper.isAppFunctionEnabled(
- functionIdentifier, targetPackage, appSearchManager, executor, callback);
+ /**
+ * Returns a boolean through a callback, indicating whether the app function is enabled.
+ *
+ * <p>This method can only check app functions owned by the caller, unlike {@link
+ * #isAppFunctionEnabled(String, String, Executor, OutcomeReceiver)}, which allows specifying a
+ * different target package.
+ *
+ * <p>If the operation fails, the callback's {@link OutcomeReceiver#onError} is called with
+ * errors:
+ *
+ * <ul>
+ * <li>{@link IllegalArgumentException}, if the function is not found or the caller does not
+ * have access to it.
+ * </ul>
+ *
+ * @param functionIdentifier the identifier of the app function to check (unique within the
+ * target package) and in most cases, these are automatically generated by the AppFunctions
+ * SDK
+ * @param executor the executor to run the request
+ * @param callback the callback to receive the function enabled check result
+ */
+ public void isAppFunctionEnabled(
+ @NonNull String functionIdentifier,
+ @NonNull Executor executor,
+ @NonNull OutcomeReceiver<Boolean, Exception> callback) {
+ isAppFunctionEnabledInternal(
+ functionIdentifier, mContext.getPackageName(), executor, callback);
}
/**
@@ -291,6 +315,25 @@ public final class AppFunctionManager {
}
}
+ private void isAppFunctionEnabledInternal(
+ @NonNull String functionIdentifier,
+ @NonNull String targetPackage,
+ @NonNull Executor executor,
+ @NonNull OutcomeReceiver<Boolean, Exception> callback) {
+ Objects.requireNonNull(functionIdentifier);
+ Objects.requireNonNull(targetPackage);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+ AppSearchManager appSearchManager = mContext.getSystemService(AppSearchManager.class);
+ if (appSearchManager == null) {
+ callback.onError(new IllegalStateException("Failed to get AppSearchManager."));
+ return;
+ }
+
+ AppFunctionManagerHelper.isAppFunctionEnabled(
+ functionIdentifier, targetPackage, appSearchManager, executor, callback);
+ }
+
private static class CallbackWrapper extends IAppFunctionEnabledCallback.Stub {
private final OutcomeReceiver<Void, Exception> mCallback;
diff --git a/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java b/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java
index 83453a9d1c71..cdf02e6f5a09 100644
--- a/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java
+++ b/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java
@@ -73,38 +73,102 @@ public final class ExecuteAppFunctionResponse implements Parcelable {
*/
public static final String PROPERTY_RETURN_VALUE = "returnValue";
- /** The call was successful. */
+ /**
+ * The call was successful.
+ *
+ * <p>This result code does not belong in an error category.
+ */
public static final int RESULT_OK = 0;
- /** The caller does not have the permission to execute an app function. */
- public static final int RESULT_DENIED = 1;
+ /**
+ * The caller does not have the permission to execute an app function.
+ *
+ * <p>This error is in the {@link #ERROR_CATEGORY_REQUEST_ERROR} category.
+ */
+ public static final int RESULT_DENIED = 1000;
+
+ /**
+ * The caller supplied invalid arguments to the execution request.
+ *
+ * <p>This error may be considered similar to {@link IllegalArgumentException}.
+ *
+ * <p>This error is in the {@link #ERROR_CATEGORY_REQUEST_ERROR} category.
+ */
+ public static final int RESULT_INVALID_ARGUMENT = 1001;
+
+ /**
+ * The caller tried to execute a disabled app function.
+ *
+ * <p>This error is in the {@link #ERROR_CATEGORY_REQUEST_ERROR} category.
+ */
+ public static final int RESULT_DISABLED = 1002;
+
+ /**
+ * The caller tried to execute a function that does not exist.
+ *
+ * <p>This error is in the {@link #ERROR_CATEGORY_REQUEST_ERROR} category.
+ */
+ public static final int RESULT_FUNCTION_NOT_FOUND = 1003;
+
+ /**
+ * An internal unexpected error coming from the system.
+ *
+ * <p>This error is in the {@link #ERROR_CATEGORY_SYSTEM} category.
+ */
+ public static final int RESULT_SYSTEM_ERROR = 2000;
+
+ /**
+ * The operation was cancelled. Use this error code to report that a cancellation is done after
+ * receiving a cancellation signal.
+ *
+ * <p>This error is in the {@link #ERROR_CATEGORY_SYSTEM} category.
+ */
+ public static final int RESULT_CANCELLED = 2001;
/**
* An unknown error occurred while processing the call in the AppFunctionService.
*
* <p>This error is thrown when the service is connected in the remote application but an
* unexpected error is thrown from the bound application.
+ *
+ * <p>This error is in the {@link #ERROR_CATEGORY_APP} category.
*/
- public static final int RESULT_APP_UNKNOWN_ERROR = 2;
+ public static final int RESULT_APP_UNKNOWN_ERROR = 3000;
- /** An internal unexpected error coming from the system. */
- public static final int RESULT_INTERNAL_ERROR = 3;
+ /**
+ * The error category is unknown.
+ *
+ * <p>This is the default value for {@link #getErrorCategory}.
+ */
+ public static final int ERROR_CATEGORY_UNKNOWN = 0;
/**
- * The caller supplied invalid arguments to the call.
+ * The error is caused by the app requesting a function execution.
*
- * <p>This error may be considered similar to {@link IllegalArgumentException}.
+ * <p>For example, the caller provided invalid parameters in the execution request e.g. an
+ * invalid function ID.
+ *
+ * <p>Errors in the category fall in the range 1000-1999 inclusive.
*/
- public static final int RESULT_INVALID_ARGUMENT = 4;
+ public static final int ERROR_CATEGORY_REQUEST_ERROR = 1;
- /** The caller tried to execute a disabled app function. */
- public static final int RESULT_DISABLED = 5;
+ /**
+ * The error is caused by an issue in the system.
+ *
+ * <p>For example, the AppFunctionService implementation is not found by the system.
+ *
+ * <p>Errors in the category fall in the range 2000-2999 inclusive.
+ */
+ public static final int ERROR_CATEGORY_SYSTEM = 2;
/**
- * The operation was cancelled. Use this error code to report that a cancellation is done after
- * receiving a cancellation signal.
+ * The error is caused by the app providing the function.
+ *
+ * <p>For example, the app crashed when the system is executing the request.
+ *
+ * <p>Errors in the category fall in the range 3000-3999 inclusive.
*/
- public static final int RESULT_CANCELLED = 6;
+ public static final int ERROR_CATEGORY_APP = 3;
/** The result code of the app function execution. */
@ResultCode private final int mResultCode;
@@ -198,6 +262,36 @@ public final class ExecuteAppFunctionResponse implements Parcelable {
}
/**
+ * Returns the error category of the {@link ExecuteAppFunctionResponse}.
+ *
+ * <p>This method categorizes errors based on their underlying cause, allowing developers to
+ * implement targeted error handling and provide more informative error messages to users. It
+ * maps ranges of result codes to specific error categories.
+ *
+ * <p>When constructing a {@link #newFailure} response, use the appropriate result code value to
+ * ensure correct categorization of the failed response.
+ *
+ * <p>This method returns {@code ERROR_CATEGORY_UNKNOWN} if the result code does not belong to
+ * any error category, for example, in the case of a successful result with {@link #RESULT_OK}.
+ *
+ * <p>See {@link ErrorCategory} for a complete list of error categories and their corresponding
+ * result code ranges.
+ */
+ @ErrorCategory
+ public int getErrorCategory() {
+ if (mResultCode >= 1000 && mResultCode < 2000) {
+ return ERROR_CATEGORY_REQUEST_ERROR;
+ }
+ if (mResultCode >= 2000 && mResultCode < 3000) {
+ return ERROR_CATEGORY_SYSTEM;
+ }
+ if (mResultCode >= 3000 && mResultCode < 4000) {
+ return ERROR_CATEGORY_APP;
+ }
+ return ERROR_CATEGORY_UNKNOWN;
+ }
+
+ /**
* Returns a generic document containing the return value of the executed function.
*
* <p>The {@link #PROPERTY_RETURN_VALUE} key can be used to obtain the return value.
@@ -280,11 +374,28 @@ public final class ExecuteAppFunctionResponse implements Parcelable {
RESULT_OK,
RESULT_DENIED,
RESULT_APP_UNKNOWN_ERROR,
- RESULT_INTERNAL_ERROR,
+ RESULT_FUNCTION_NOT_FOUND,
+ RESULT_SYSTEM_ERROR,
RESULT_INVALID_ARGUMENT,
RESULT_DISABLED,
RESULT_CANCELLED
})
@Retention(RetentionPolicy.SOURCE)
public @interface ResultCode {}
+
+ /**
+ * Error categories.
+ *
+ * @hide
+ */
+ @IntDef(
+ prefix = {"ERROR_CATEGORY_"},
+ value = {
+ ERROR_CATEGORY_UNKNOWN,
+ ERROR_CATEGORY_REQUEST_ERROR,
+ ERROR_CATEGORY_APP,
+ ERROR_CATEGORY_SYSTEM
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ErrorCategory {}
}
diff --git a/core/java/android/app/performance.aconfig b/core/java/android/app/performance.aconfig
index 7484a8558841..f51f748bc71f 100644
--- a/core/java/android/app/performance.aconfig
+++ b/core/java/android/app/performance.aconfig
@@ -7,7 +7,7 @@ flag {
is_exported: true
is_fixed_read_only: true
description: "PropertyInvalidatedCache uses shared memory for nonces."
- bug: "366552454"
+ bug: "360897450"
}
flag {
@@ -16,5 +16,5 @@ flag {
is_exported: true
is_fixed_read_only: true
description: "Enforce PropertyInvalidatedCache.setTestMode() protocol"
- bug: "366552454"
+ bug: "360897450"
}
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index 72f992ab3917..79eeaa914771 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -306,6 +306,38 @@ public class AppWidgetHost {
}
/**
+ * Returns an {@link IntentSender} for starting the configuration activity for the widget.
+ *
+ * @return The {@link IntentSender} or null if service is currently unavailable
+ *
+ * @throws android.content.ActivityNotFoundException If configuration activity is not found.
+ *
+ * @see #startAppWidgetConfigureActivityForResult
+ *
+ * @hide
+ */
+ @Nullable
+ public final IntentSender getIntentSenderForConfigureActivity(int appWidgetId,
+ int intentFlags) {
+ if (sService == null) {
+ return null;
+ }
+
+ IntentSender intentSender;
+ try {
+ intentSender = sService.createAppWidgetConfigIntentSender(mContextOpPackageName,
+ appWidgetId, intentFlags);
+ } catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+
+ if (intentSender == null) {
+ throw new ActivityNotFoundException();
+ }
+ return intentSender;
+ }
+
+ /**
* Starts an app widget provider configure activity for result on behalf of the caller.
* Use this method if the provider is in another profile as you are not allowed to start
* an activity in another profile. You can optionally provide a request code that is
@@ -330,18 +362,11 @@ public class AppWidgetHost {
return;
}
try {
- IntentSender intentSender = sService.createAppWidgetConfigIntentSender(
- mContextOpPackageName, appWidgetId, intentFlags);
- if (intentSender != null) {
- activity.startIntentSenderForResult(intentSender, requestCode, null, 0, 0, 0,
- options);
- } else {
- throw new ActivityNotFoundException();
- }
+ IntentSender intentSender = getIntentSenderForConfigureActivity(appWidgetId,
+ intentFlags);
+ activity.startIntentSenderForResult(intentSender, requestCode, null, 0, 0, 0, options);
} catch (IntentSender.SendIntentException e) {
throw new ActivityNotFoundException();
- } catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
}
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 1d26b77af5c7..186f7b3e111c 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -6677,8 +6677,8 @@ public abstract class Context {
*
* @see #getSystemService(String)
* @see android.telephony.satellite.SatelliteManager
- * @hide
*/
+ @FlaggedApi(com.android.internal.telephony.flags.Flags.FLAG_SATELLITE_STATE_CHANGE_LISTENER)
public static final String SATELLITE_SERVICE = "satellite";
/**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 2fdf2589e13d..6fa5a9b82858 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -899,7 +899,7 @@ public class Intent implements Parcelable, Cloneable {
boolean isForeign = (intent.mLocalFlags & LOCAL_FLAG_FROM_PARCEL) != 0;
boolean isWithoutTrustedCreatorToken =
(intent.mLocalFlags & Intent.LOCAL_FLAG_TRUSTED_CREATOR_TOKEN_PRESENT) == 0;
- if (isForeign && isWithoutTrustedCreatorToken) {
+ if (isForeign && isWithoutTrustedCreatorToken && preventIntentRedirect()) {
intent.addExtendedFlags(EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN);
}
}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 1137e1e89f67..16d82caa6c1a 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -775,6 +775,46 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
new Key<int[]>("android.colorCorrection.availableAberrationModes", int[].class);
/**
+ * <p>The range of supported color temperature values for
+ * {@link CaptureRequest#COLOR_CORRECTION_COLOR_TEMPERATURE android.colorCorrection.colorTemperature}.</p>
+ * <p>This key lists the valid range of color temperature values for
+ * {@link CaptureRequest#COLOR_CORRECTION_COLOR_TEMPERATURE android.colorCorrection.colorTemperature} supported by this camera device.</p>
+ * <p>This key will be null on devices that do not support CCT mode for
+ * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
+ * <p><b>Range of valid values:</b><br></p>
+ * <p>The minimum supported range will be [2856K,6500K]. The maximum supported
+ * range will be [1000K,40000K].</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_COLOR_TEMPERATURE
+ * @see CaptureRequest#COLOR_CORRECTION_MODE
+ */
+ @PublicKey
+ @NonNull
+ @FlaggedApi(Flags.FLAG_COLOR_TEMPERATURE)
+ public static final Key<android.util.Range<Integer>> COLOR_CORRECTION_COLOR_TEMPERATURE_RANGE =
+ new Key<android.util.Range<Integer>>("android.colorCorrection.colorTemperatureRange", new TypeReference<android.util.Range<Integer>>() {{ }});
+
+ /**
+ * <p>List of color correction modes for {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} that are
+ * supported by this camera device.</p>
+ * <p>This key lists the valid modes for {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}. If no
+ * color correction modes are available for a device, this key will be null.</p>
+ * <p>Camera devices that have a FULL hardware level will always include at least
+ * FAST, HIGH_QUALITY, and TRANSFORM_MATRIX modes.</p>
+ * <p><b>Range of valid values:</b><br>
+ * Any value listed in {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_MODE
+ */
+ @PublicKey
+ @NonNull
+ @FlaggedApi(Flags.FLAG_COLOR_TEMPERATURE)
+ public static final Key<int[]> COLOR_CORRECTION_AVAILABLE_MODES =
+ new Key<int[]>("android.colorCorrection.availableModes", int[].class);
+
+ /**
* <p>List of auto-exposure antibanding modes for {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode} that are
* supported by this camera device.</p>
* <p>Not all of the auto-exposure anti-banding modes may be
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index acb48f328f1a..86bbd4a57a63 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2169,6 +2169,22 @@ public abstract class CameraMetadata<TKey> {
*/
public static final int COLOR_CORRECTION_MODE_HIGH_QUALITY = 2;
+ /**
+ * <p>Use
+ * {@link CaptureRequest#COLOR_CORRECTION_COLOR_TEMPERATURE android.colorCorrection.colorTemperature} and
+ * {@link CaptureRequest#COLOR_CORRECTION_COLOR_TINT android.colorCorrection.colorTint} to adjust the white balance based
+ * on correlated color temperature.</p>
+ * <p>If AWB is enabled with <code>{@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} != OFF</code>, then
+ * CCT is ignored.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_COLOR_TEMPERATURE
+ * @see CaptureRequest#COLOR_CORRECTION_COLOR_TINT
+ * @see CaptureRequest#CONTROL_AWB_MODE
+ * @see CaptureRequest#COLOR_CORRECTION_MODE
+ */
+ @FlaggedApi(Flags.FLAG_COLOR_TEMPERATURE)
+ public static final int COLOR_CORRECTION_MODE_CCT = 3;
+
//
// Enumeration values for CaptureRequest#COLOR_CORRECTION_ABERRATION_MODE
//
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index a5c5a9952879..8142bbe9b838 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1086,11 +1086,17 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* <li>{@link #COLOR_CORRECTION_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
* </ul>
*
+ * <p><b>Available values for this device:</b><br>
+ * Starting from API level 36, {@link CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_MODES android.colorCorrection.availableModes}
+ * can be used to check the list of supported values. Prior to API level 36,
+ * TRANSFORM_MATRIX, HIGH_QUALITY, and FAST are guaranteed to be available
+ * as valid modes on devices that support this key.</p>
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
* <p><b>Full capability</b> -
* Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
* {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
*
+ * @see CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_MODES
* @see CaptureRequest#COLOR_CORRECTION_GAINS
* @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
@@ -1195,6 +1201,60 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
new Key<Integer>("android.colorCorrection.aberrationMode", int.class);
/**
+ * <p>Specifies the color temperature for CCT mode in Kelvin
+ * to adjust the white balance of the image.</p>
+ * <p>Sets the color temperature in Kelvin units for when
+ * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is CCT to adjust the
+ * white balance of the image.</p>
+ * <p>If CCT mode is enabled without a requested color temperature,
+ * a default value will be set by the camera device. The default value can be
+ * retrieved by checking the corresponding capture result. Color temperatures
+ * requested outside the advertised {@link CameraCharacteristics#COLOR_CORRECTION_COLOR_TEMPERATURE_RANGE android.colorCorrection.colorTemperatureRange}
+ * will be clamped.</p>
+ * <p><b>Units</b>: Kelvin</p>
+ * <p><b>Range of valid values:</b><br>
+ * {@link CameraCharacteristics#COLOR_CORRECTION_COLOR_TEMPERATURE_RANGE android.colorCorrection.colorTemperatureRange}</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ *
+ * @see CameraCharacteristics#COLOR_CORRECTION_COLOR_TEMPERATURE_RANGE
+ * @see CaptureRequest#COLOR_CORRECTION_MODE
+ */
+ @PublicKey
+ @NonNull
+ @FlaggedApi(Flags.FLAG_COLOR_TEMPERATURE)
+ public static final Key<Integer> COLOR_CORRECTION_COLOR_TEMPERATURE =
+ new Key<Integer>("android.colorCorrection.colorTemperature", int.class);
+
+ /**
+ * <p>Specifies the color tint for CCT mode to adjust the white
+ * balance of the image.</p>
+ * <p>Sets the color tint for when {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}
+ * is CCT to adjust the white balance of the image.</p>
+ * <p>If CCT mode is enabled without a requested color tint,
+ * a default value will be set by the camera device. The default value can be
+ * retrieved by checking the corresponding capture result. Color tints requested
+ * outside the supported range will be clamped to the nearest limit (-50 or +50).</p>
+ * <p><b>Units</b>: D_uv defined as the distance from the Planckian locus on the CIE 1931 xy
+ * chromaticity diagram, with the range ±50 mapping to ±0.01 D_uv</p>
+ * <p><b>Range of valid values:</b><br>
+ * The supported range, -50 to +50, corresponds to a D_uv distance
+ * of ±0.01 below and above the Planckian locus. Some camera devices may have
+ * limitations to achieving the full ±0.01 D_uv range at some color temperatures
+ * (e.g., below 1500K). In these cases, the applied D_uv value may be clamped and
+ * the actual color tint will be reported in the {@link CaptureRequest#COLOR_CORRECTION_COLOR_TINT android.colorCorrection.colorTint}
+ * result.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_COLOR_TINT
+ * @see CaptureRequest#COLOR_CORRECTION_MODE
+ */
+ @PublicKey
+ @NonNull
+ @FlaggedApi(Flags.FLAG_COLOR_TEMPERATURE)
+ public static final Key<Integer> COLOR_CORRECTION_COLOR_TINT =
+ new Key<Integer>("android.colorCorrection.colorTint", int.class);
+
+ /**
* <p>The desired setting for the camera device's auto-exposure
* algorithm's antibanding compensation.</p>
* <p>Some kinds of lighting fixtures, such as some fluorescent
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index a6bdb3f1bb07..ae72ca40fc5a 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -487,11 +487,17 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <li>{@link #COLOR_CORRECTION_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
* </ul>
*
+ * <p><b>Available values for this device:</b><br>
+ * Starting from API level 36, {@link CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_MODES android.colorCorrection.availableModes}
+ * can be used to check the list of supported values. Prior to API level 36,
+ * TRANSFORM_MATRIX, HIGH_QUALITY, and FAST are guaranteed to be available
+ * as valid modes on devices that support this key.</p>
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
* <p><b>Full capability</b> -
* Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
* {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
*
+ * @see CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_MODES
* @see CaptureRequest#COLOR_CORRECTION_GAINS
* @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
@@ -596,6 +602,60 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
new Key<Integer>("android.colorCorrection.aberrationMode", int.class);
/**
+ * <p>Specifies the color temperature for CCT mode in Kelvin
+ * to adjust the white balance of the image.</p>
+ * <p>Sets the color temperature in Kelvin units for when
+ * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is CCT to adjust the
+ * white balance of the image.</p>
+ * <p>If CCT mode is enabled without a requested color temperature,
+ * a default value will be set by the camera device. The default value can be
+ * retrieved by checking the corresponding capture result. Color temperatures
+ * requested outside the advertised {@link CameraCharacteristics#COLOR_CORRECTION_COLOR_TEMPERATURE_RANGE android.colorCorrection.colorTemperatureRange}
+ * will be clamped.</p>
+ * <p><b>Units</b>: Kelvin</p>
+ * <p><b>Range of valid values:</b><br>
+ * {@link CameraCharacteristics#COLOR_CORRECTION_COLOR_TEMPERATURE_RANGE android.colorCorrection.colorTemperatureRange}</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ *
+ * @see CameraCharacteristics#COLOR_CORRECTION_COLOR_TEMPERATURE_RANGE
+ * @see CaptureRequest#COLOR_CORRECTION_MODE
+ */
+ @PublicKey
+ @NonNull
+ @FlaggedApi(Flags.FLAG_COLOR_TEMPERATURE)
+ public static final Key<Integer> COLOR_CORRECTION_COLOR_TEMPERATURE =
+ new Key<Integer>("android.colorCorrection.colorTemperature", int.class);
+
+ /**
+ * <p>Specifies the color tint for CCT mode to adjust the white
+ * balance of the image.</p>
+ * <p>Sets the color tint for when {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}
+ * is CCT to adjust the white balance of the image.</p>
+ * <p>If CCT mode is enabled without a requested color tint,
+ * a default value will be set by the camera device. The default value can be
+ * retrieved by checking the corresponding capture result. Color tints requested
+ * outside the supported range will be clamped to the nearest limit (-50 or +50).</p>
+ * <p><b>Units</b>: D_uv defined as the distance from the Planckian locus on the CIE 1931 xy
+ * chromaticity diagram, with the range ±50 mapping to ±0.01 D_uv</p>
+ * <p><b>Range of valid values:</b><br>
+ * The supported range, -50 to +50, corresponds to a D_uv distance
+ * of ±0.01 below and above the Planckian locus. Some camera devices may have
+ * limitations to achieving the full ±0.01 D_uv range at some color temperatures
+ * (e.g., below 1500K). In these cases, the applied D_uv value may be clamped and
+ * the actual color tint will be reported in the {@link CaptureRequest#COLOR_CORRECTION_COLOR_TINT android.colorCorrection.colorTint}
+ * result.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_COLOR_TINT
+ * @see CaptureRequest#COLOR_CORRECTION_MODE
+ */
+ @PublicKey
+ @NonNull
+ @FlaggedApi(Flags.FLAG_COLOR_TEMPERATURE)
+ public static final Key<Integer> COLOR_CORRECTION_COLOR_TINT =
+ new Key<Integer>("android.colorCorrection.colorTint", int.class);
+
+ /**
* <p>The desired setting for the camera device's auto-exposure
* algorithm's antibanding compensation.</p>
* <p>Some kinds of lighting fixtures, such as some fluorescent
diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
index 6297318dfb25..9806ab25745c 100644
--- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java
+++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
@@ -76,14 +76,14 @@ public final class MessageQueue {
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
private IdleHandler[] mPendingIdleHandlers;
- private boolean mLegacyQuitting;
+ private boolean mQuitting;
// Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
- private boolean mLegacyBlocked;
+ private boolean mBlocked;
// Tracks the number of async message. We use this in enqueueMessage() to avoid searching the
// queue for async messages when inserting a message at the tail.
- private int mLegacyAsyncMessageCount;
+ private int mAsyncMessageCount;
/*
* Select between two implementations of message queue. The legacy implementation is used
@@ -261,8 +261,8 @@ public final class MessageQueue {
private boolean isPollingLocked() {
// If the loop is quitting then it must not be idling.
- // We can assume mPtr != 0 when mLegacyQuitting is false.
- return !mLegacyQuitting && nativeIsPolling(mPtr);
+ // We can assume mPtr != 0 when mQuitting is false.
+ return !mQuitting && nativeIsPolling(mPtr);
}
/**
@@ -743,7 +743,7 @@ public final class MessageQueue {
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
- mLegacyBlocked = false;
+ mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
if (prevMsg.next == null) {
@@ -759,7 +759,7 @@ public final class MessageQueue {
if (DEBUG) Log.v(TAG_L, "Returning message: " + msg);
msg.markInUse();
if (msg.isAsynchronous()) {
- mLegacyAsyncMessageCount--;
+ mAsyncMessageCount--;
}
if (TRACE) {
Trace.setCounter("MQ.Delivered", mMessagesDelivered.incrementAndGet());
@@ -772,7 +772,7 @@ public final class MessageQueue {
}
// Process the quit message now that all pending messages have been handled.
- if (mLegacyQuitting) {
+ if (mQuitting) {
dispose();
return null;
}
@@ -786,7 +786,7 @@ public final class MessageQueue {
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
- mLegacyBlocked = true;
+ mBlocked = true;
continue;
}
@@ -845,10 +845,10 @@ public final class MessageQueue {
}
} else {
synchronized (this) {
- if (mLegacyQuitting) {
+ if (mQuitting) {
return;
}
- mLegacyQuitting = true;
+ mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
@@ -856,7 +856,7 @@ public final class MessageQueue {
removeAllMessagesLocked();
}
- // We can assume mPtr != 0 because mLegacyQuitting was previously false.
+ // We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
@@ -1042,8 +1042,8 @@ public final class MessageQueue {
p.recycleUnchecked();
// If the loop is quitting then it is already awake.
- // We can assume mPtr != 0 when mLegacyQuitting is false.
- if (needWake && !mLegacyQuitting) {
+ // We can assume mPtr != 0 when mQuitting is false.
+ if (needWake && !mQuitting) {
nativeWake(mPtr);
}
}
@@ -1067,7 +1067,7 @@ public final class MessageQueue {
throw new IllegalStateException(msg + " This message is already in use.");
}
- if (mLegacyQuitting) {
+ if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG_L, e.getMessage(), e);
@@ -1083,7 +1083,7 @@ public final class MessageQueue {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
- needWake = mLegacyBlocked;
+ needWake = mBlocked;
if (p == null) {
mLast = mMessages;
}
@@ -1091,14 +1091,14 @@ public final class MessageQueue {
// Message is to be inserted at tail or middle of queue. Usually we don't have to
// wake up the event queue unless there is a barrier at the head of the queue and
// the message is the earliest asynchronous message in the queue.
- needWake = mLegacyBlocked && p.target == null && msg.isAsynchronous();
+ needWake = mBlocked && p.target == null && msg.isAsynchronous();
// For readability, we split this portion of the function into two blocks based on
// whether tail tracking is enabled. This has a minor implication for the case
// where tail tracking is disabled. See the comment below.
if (Flags.messageQueueTailTracking()) {
if (when >= mLast.when) {
- needWake = needWake && mLegacyAsyncMessageCount == 0;
+ needWake = needWake && mAsyncMessageCount == 0;
msg.next = null;
mLast.next = msg;
mLast = msg;
@@ -1156,10 +1156,10 @@ public final class MessageQueue {
}
if (msg.isAsynchronous()) {
- mLegacyAsyncMessageCount++;
+ mAsyncMessageCount++;
}
- // We can assume mPtr != 0 because mLegacyQuitting is false.
+ // We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
@@ -1313,7 +1313,7 @@ public final class MessageQueue {
Message n = p.next;
mMessages = n;
if (p.isAsynchronous()) {
- mLegacyAsyncMessageCount--;
+ mAsyncMessageCount--;
}
p.recycleUnchecked();
p = n;
@@ -1331,7 +1331,7 @@ public final class MessageQueue {
&& (object == null || n.obj == object)) {
Message nn = n.next;
if (n.isAsynchronous()) {
- mLegacyAsyncMessageCount--;
+ mAsyncMessageCount--;
}
n.recycleUnchecked();
p.next = nn;
@@ -1365,7 +1365,7 @@ public final class MessageQueue {
Message n = p.next;
mMessages = n;
if (p.isAsynchronous()) {
- mLegacyAsyncMessageCount--;
+ mAsyncMessageCount--;
}
p.recycleUnchecked();
p = n;
@@ -1383,7 +1383,7 @@ public final class MessageQueue {
&& (object == null || object.equals(n.obj))) {
Message nn = n.next;
if (n.isAsynchronous()) {
- mLegacyAsyncMessageCount--;
+ mAsyncMessageCount--;
}
n.recycleUnchecked();
p.next = nn;
@@ -1416,7 +1416,7 @@ public final class MessageQueue {
Message n = p.next;
mMessages = n;
if (p.isAsynchronous()) {
- mLegacyAsyncMessageCount--;
+ mAsyncMessageCount--;
}
p.recycleUnchecked();
p = n;
@@ -1434,7 +1434,7 @@ public final class MessageQueue {
&& (object == null || n.obj == object)) {
Message nn = n.next;
if (n.isAsynchronous()) {
- mLegacyAsyncMessageCount--;
+ mAsyncMessageCount--;
}
n.recycleUnchecked();
p.next = nn;
@@ -1479,7 +1479,7 @@ public final class MessageQueue {
Message n = p.next;
mMessages = n;
if (p.isAsynchronous()) {
- mLegacyAsyncMessageCount--;
+ mAsyncMessageCount--;
}
p.recycleUnchecked();
p = n;
@@ -1497,7 +1497,7 @@ public final class MessageQueue {
&& (object == null || object.equals(n.obj))) {
Message nn = n.next;
if (n.isAsynchronous()) {
- mLegacyAsyncMessageCount--;
+ mAsyncMessageCount--;
}
n.recycleUnchecked();
p.next = nn;
@@ -1541,7 +1541,7 @@ public final class MessageQueue {
Message n = p.next;
mMessages = n;
if (p.isAsynchronous()) {
- mLegacyAsyncMessageCount--;
+ mAsyncMessageCount--;
}
p.recycleUnchecked();
p = n;
@@ -1558,7 +1558,7 @@ public final class MessageQueue {
if (n.target == h && (object == null || n.obj == object)) {
Message nn = n.next;
if (n.isAsynchronous()) {
- mLegacyAsyncMessageCount--;
+ mAsyncMessageCount--;
}
n.recycleUnchecked();
p.next = nn;
@@ -1603,7 +1603,7 @@ public final class MessageQueue {
Message n = p.next;
mMessages = n;
if (p.isAsynchronous()) {
- mLegacyAsyncMessageCount--;
+ mAsyncMessageCount--;
}
p.recycleUnchecked();
p = n;
@@ -1620,7 +1620,7 @@ public final class MessageQueue {
if (n.target == h && (object == null || object.equals(n.obj))) {
Message nn = n.next;
if (n.isAsynchronous()) {
- mLegacyAsyncMessageCount--;
+ mAsyncMessageCount--;
}
n.recycleUnchecked();
p.next = nn;
@@ -1644,7 +1644,7 @@ public final class MessageQueue {
}
mMessages = null;
mLast = null;
- mLegacyAsyncMessageCount = 0;
+ mAsyncMessageCount = 0;
}
private void removeAllFutureMessagesLocked() {
@@ -1672,7 +1672,7 @@ public final class MessageQueue {
p = n;
n = p.next;
if (p.isAsynchronous()) {
- mLegacyAsyncMessageCount--;
+ mAsyncMessageCount--;
}
p.recycleUnchecked();
} while (n != null);
@@ -1780,7 +1780,7 @@ public final class MessageQueue {
n++;
}
pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked()
- + ", quitting=" + mLegacyQuitting + ")");
+ + ", quitting=" + mQuitting + ")");
}
}
@@ -1824,7 +1824,7 @@ public final class MessageQueue {
msg.dumpDebug(proto, MessageQueueProto.MESSAGES);
}
proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPollingLocked());
- proto.write(MessageQueueProto.IS_QUITTING, mLegacyQuitting);
+ proto.write(MessageQueueProto.IS_QUITTING, mQuitting);
}
proto.end(messageQueueToken);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index fa99f3563de9..4bc8fe0a974c 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -5502,10 +5502,14 @@ public class UserManager {
Manifest.permission.CREATE_USERS,
Manifest.permission.QUERY_USERS}, conditional = true)
public @NonNull int[] getProfileIds(@UserIdInt int userId, boolean enabledOnly) {
- try {
- return mService.getProfileIds(userId, enabledOnly);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
+ if (android.multiuser.Flags.cacheProfileIdsReadOnly()) {
+ return enabledOnly ? getEnabledProfileIds(userId) : getProfileIdsWithDisabled(userId);
+ } else {
+ try {
+ return mService.getProfileIds(userId, enabledOnly);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
}
}
@@ -5518,8 +5522,14 @@ public class UserManager {
Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS,
Manifest.permission.QUERY_USERS}, conditional = true)
+ @CachedProperty(api = "user_manager_users")
public int[] getProfileIdsWithDisabled(@UserIdInt int userId) {
- return getProfileIds(userId, false /* enabledOnly */);
+ if (android.multiuser.Flags.cacheProfileIdsReadOnly()) {
+ return UserManagerCache.getProfileIdsWithDisabled(
+ (Integer userIdentifuer) -> mService.getProfileIds(userIdentifuer, false), userId);
+ } else {
+ return getProfileIds(userId, false /* enabledOnly */);
+ }
}
/**
@@ -5530,8 +5540,21 @@ public class UserManager {
Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS,
Manifest.permission.QUERY_USERS}, conditional = true)
+ @CachedProperty(api = "user_manager_users_enabled")
public int[] getEnabledProfileIds(@UserIdInt int userId) {
- return getProfileIds(userId, true /* enabledOnly */);
+ if (android.multiuser.Flags.cacheProfileIdsReadOnly()) {
+ return UserManagerCache.getEnabledProfileIds(
+ (Integer userIdentifuer) -> mService.getProfileIds(userIdentifuer, true), userId);
+ } else {
+ return getProfileIds(userId, true /* enabledOnly */);
+ }
+ }
+
+ /** @hide */
+ public static final void invalidateEnabledProfileIds() {
+ if (android.multiuser.Flags.cacheProfileIdsReadOnly()) {
+ UserManagerCache.invalidateEnabledProfileIds();
+ }
}
/**
@@ -6443,6 +6466,21 @@ public class UserManager {
if (android.multiuser.Flags.cacheProfileParentReadOnly()) {
UserManagerCache.invalidateProfileParent();
}
+ invalidateEnabledProfileIds();
+ }
+
+ /**
+ * Invalidate caches when related to specific user info flags change.
+ *
+ * @param flag a combination of FLAG_ constants, from the list in
+ * {@link UserInfo#UserInfoFlag}, whose value has changed and the associated
+ * invalidations must therefore be performed.
+ * @hide
+ */
+ public static final void invalidateOnUserInfoFlagChange(@UserInfoFlag int flags) {
+ if ((flags & UserInfo.FLAG_DISABLED) > 0) {
+ invalidateEnabledProfileIds();
+ }
}
/**
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index a3844e244edb..0cffd9f990fd 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -1740,7 +1740,9 @@ public abstract class VibrationEffect implements Parcelable {
*
* <p>The waveform envelope builder offers more flexibility for creating waveform effects,
* allowing control over vibration amplitude and frequency via smooth transitions between
- * values.
+ * values. The waveform will start the first transition from the vibrator off state, using
+ * the same frequency of the first control point. To provide a different initial vibration
+ * frequency, use {@link #startWaveformEnvelope(float)}.
*
* <p>Note: To check whether waveform envelope effects are supported, use
* {@link Vibrator#areEnvelopeEffectsSupported()}.
@@ -1754,6 +1756,32 @@ public abstract class VibrationEffect implements Parcelable {
}
/**
+ * Start building a waveform vibration with an initial frequency.
+ *
+ * <p>The waveform envelope builder offers more flexibility for creating waveform effects,
+ * allowing control over vibration amplitude and frequency via smooth transitions between
+ * values.
+ *
+ * <p>This is the same as {@link #startWaveformEnvelope()}, but the waveform will start
+ * vibrating at given frequency, in hertz, while it transitions to the new amplitude and
+ * frequency of the first control point.
+ *
+ * <p>Note: To check whether waveform envelope effects are supported, use
+ * {@link Vibrator#areEnvelopeEffectsSupported()}.
+ *
+ * @param initialFrequencyHz The starting frequency of the vibration, in hertz. Must be greater
+ * than zero.
+ *
+ * @see VibrationEffect.WaveformEnvelopeBuilder
+ */
+ @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+ @NonNull
+ public static VibrationEffect.WaveformEnvelopeBuilder startWaveformEnvelope(
+ @FloatRange(from = 0) float initialFrequencyHz) {
+ return new WaveformEnvelopeBuilder(initialFrequencyHz);
+ }
+
+ /**
* A builder for waveform effects described by its envelope.
*
* <p>Waveform effect envelopes are defined by one or more control points describing a target
@@ -1810,6 +1838,10 @@ public abstract class VibrationEffect implements Parcelable {
private WaveformEnvelopeBuilder() {}
+ private WaveformEnvelopeBuilder(float initialFrequency) {
+ mLastFrequencyHz = initialFrequency;
+ }
+
/**
* Adds a new control point to the end of this waveform envelope.
*
@@ -1841,7 +1873,7 @@ public abstract class VibrationEffect implements Parcelable {
@FloatRange(from = 0, to = 1) float amplitude,
@FloatRange(from = 0) float frequencyHz, int timeMillis) {
- if (mSegments.isEmpty()) {
+ if (mLastFrequencyHz == 0) {
mLastFrequencyHz = frequencyHz;
}
diff --git a/core/java/android/os/vibrator/PwlePoint.java b/core/java/android/os/vibrator/PwlePoint.java
new file mode 100644
index 000000000000..ea3ae6c4649d
--- /dev/null
+++ b/core/java/android/os/vibrator/PwlePoint.java
@@ -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 android.os.vibrator;
+
+import java.util.Objects;
+
+/**
+ * A {@link PwlePoint} represents a single point in an envelope vibration effect. Defined by its
+ * amplitude, frequency and time to transition to this point from the previous one in the envelope.
+ *
+ * @hide
+ */
+public final class PwlePoint {
+ private final float mAmplitude;
+ private final float mFrequencyHz;
+ private final int mTimeMillis;
+
+ /** @hide */
+ public PwlePoint(float amplitude, float frequencyHz, int timeMillis) {
+ mAmplitude = amplitude;
+ mFrequencyHz = frequencyHz;
+ mTimeMillis = timeMillis;
+ }
+
+ public float getAmplitude() {
+ return mAmplitude;
+ }
+
+ public float getFrequencyHz() {
+ return mFrequencyHz;
+ }
+
+ public int getTimeMillis() {
+ return mTimeMillis;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof PwlePoint)) {
+ return false;
+ }
+ PwlePoint other = (PwlePoint) obj;
+ return Float.compare(mAmplitude, other.mAmplitude) == 0
+ && Float.compare(mFrequencyHz, other.mFrequencyHz) == 0
+ && mTimeMillis == other.mTimeMillis;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mAmplitude, mFrequencyHz, mTimeMillis);
+ }
+}
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 7944be140960..6a4932211f27 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -314,3 +314,21 @@ flag {
description: "Enable AppOp mode caching in AppOpsManager"
bug: "366013082"
}
+
+flag {
+ name: "permission_tree_apis_deprecated"
+ is_fixed_read_only: true
+ is_exported: true
+ namespace: "permissions"
+ description: "This flag is used to deprecate permission tree related APIs"
+ bug: "376535612"
+}
+
+flag {
+ name: "enable_otp_in_text_classifiers"
+ is_fixed_read_only: true
+ is_exported: true
+ namespace: "permissions"
+ description: "Enables ExtServices to leverage TextClassifier for OTP detection"
+ bug: "351976749"
+}
diff --git a/core/java/android/security/advancedprotection/AdvancedProtectionFeature.aidl b/core/java/android/security/advancedprotection/AdvancedProtectionFeature.aidl
new file mode 100644
index 000000000000..3ecef0248e1f
--- /dev/null
+++ b/core/java/android/security/advancedprotection/AdvancedProtectionFeature.aidl
@@ -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 android.security.advancedprotection;
+
+/**
+ * Represents an advanced protection feature providing protections
+ * @hide
+ */
+parcelable AdvancedProtectionFeature; \ No newline at end of file
diff --git a/core/java/android/security/advancedprotection/AdvancedProtectionFeature.java b/core/java/android/security/advancedprotection/AdvancedProtectionFeature.java
new file mode 100644
index 000000000000..a086bf7f8b08
--- /dev/null
+++ b/core/java/android/security/advancedprotection/AdvancedProtectionFeature.java
@@ -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 android.security.advancedprotection;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.security.Flags;
+
+/**
+ * An advanced protection feature providing protections.
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_AAPM_API)
+@SystemApi
+public final class AdvancedProtectionFeature implements Parcelable {
+ private final String mId;
+
+ /**
+ * Create an object identifying an Advanced Protection feature for AdvancedProtectionManager
+ * @param id A unique ID to identify this feature. It is used by Settings screens to display
+ * information about this feature.
+ */
+ public AdvancedProtectionFeature(@NonNull String id) {
+ mId = id;
+ }
+
+ private AdvancedProtectionFeature(Parcel in) {
+ mId = in.readString8();
+ }
+
+ /**
+ * @return the unique ID representing this feature
+ */
+ @NonNull
+ public String getId() {
+ return mId;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString8(mId);
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<AdvancedProtectionFeature> CREATOR =
+ new Parcelable.Creator<>() {
+ public AdvancedProtectionFeature createFromParcel(Parcel in) {
+ return new AdvancedProtectionFeature(in);
+ }
+
+ public AdvancedProtectionFeature[] newArray(int size) {
+ return new AdvancedProtectionFeature[size];
+ }
+ };
+}
diff --git a/core/java/android/security/advancedprotection/AdvancedProtectionManager.java b/core/java/android/security/advancedprotection/AdvancedProtectionManager.java
index 43b6ebe2a735..6f3e3d8f0d3b 100644
--- a/core/java/android/security/advancedprotection/AdvancedProtectionManager.java
+++ b/core/java/android/security/advancedprotection/AdvancedProtectionManager.java
@@ -29,6 +29,7 @@ import android.os.RemoteException;
import android.security.Flags;
import android.util.Log;
+import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
@@ -41,7 +42,7 @@ import java.util.concurrent.Executor;
*/
@FlaggedApi(Flags.FLAG_AAPM_API)
@SystemService(Context.ADVANCED_PROTECTION_SERVICE)
-public class AdvancedProtectionManager {
+public final class AdvancedProtectionManager {
private static final String TAG = "AdvancedProtectionMgr";
private final ConcurrentHashMap<Callback, IAdvancedProtectionCallback>
@@ -147,6 +148,22 @@ public class AdvancedProtectionManager {
}
/**
+ * Returns the list of advanced protection features which are available on this device.
+ *
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ @RequiresPermission(Manifest.permission.SET_ADVANCED_PROTECTION_MODE)
+ public List<AdvancedProtectionFeature> getAdvancedProtectionFeatures() {
+ try {
+ return mService.getAdvancedProtectionFeatures();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* A callback class for monitoring changes to Advanced Protection state
*
* <p>To register a callback, implement this interface, and register it with
diff --git a/core/java/android/security/advancedprotection/IAdvancedProtectionService.aidl b/core/java/android/security/advancedprotection/IAdvancedProtectionService.aidl
index ef0abf4f23a0..68307632027a 100644
--- a/core/java/android/security/advancedprotection/IAdvancedProtectionService.aidl
+++ b/core/java/android/security/advancedprotection/IAdvancedProtectionService.aidl
@@ -16,6 +16,7 @@
package android.security.advancedprotection;
+import android.security.advancedprotection.AdvancedProtectionFeature;
import android.security.advancedprotection.IAdvancedProtectionCallback;
/**
@@ -32,4 +33,6 @@ interface IAdvancedProtectionService {
void unregisterAdvancedProtectionCallback(IAdvancedProtectionCallback callback);
@EnforcePermission("SET_ADVANCED_PROTECTION_MODE")
void setAdvancedProtectionEnabled(boolean enabled);
+ @EnforcePermission("SET_ADVANCED_PROTECTION_MODE")
+ List<AdvancedProtectionFeature> getAdvancedProtectionFeatures();
} \ No newline at end of file
diff --git a/core/java/android/security/responsible_apis_flags.aconfig b/core/java/android/security/responsible_apis_flags.aconfig
index dec28c34ae5b..5995760a41ec 100644
--- a/core/java/android/security/responsible_apis_flags.aconfig
+++ b/core/java/android/security/responsible_apis_flags.aconfig
@@ -87,6 +87,14 @@ flag {
}
flag {
+ name: "prevent_intent_redirect_show_toast"
+ namespace: "responsible_apis"
+ description: "Prevent intent redirect attacks by showing a toast when activity start is blocked"
+ bug: "361143368"
+ is_fixed_read_only: true
+}
+
+flag {
name: "enable_intent_matching_flags"
is_exported: true
namespace: "permissions"
diff --git a/core/java/android/service/contextualsearch/OWNERS b/core/java/android/service/contextualsearch/OWNERS
index b7238721bc60..c435bd87be21 100644
--- a/core/java/android/service/contextualsearch/OWNERS
+++ b/core/java/android/service/contextualsearch/OWNERS
@@ -1,2 +1,3 @@
srazdan@google.com
-hackz@google.com
+hyunyoungs@google.com
+awickham@google.com
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 4d50a450490e..1dab2cf75594 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -47,6 +47,8 @@ import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsCallSession;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.MediaQualityStatus;
+import android.telephony.satellite.SatelliteStateChangeListener;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -55,12 +57,14 @@ import com.android.internal.listeners.ListenerExecutor;
import com.android.internal.telephony.ICarrierConfigChangeListener;
import com.android.internal.telephony.ICarrierPrivilegesCallback;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
+import com.android.internal.telephony.ISatelliteStateChangeListener;
import com.android.internal.telephony.ITelephonyRegistry;
import com.android.server.telecom.flags.Flags;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.WeakHashMap;
@@ -1482,6 +1486,111 @@ public class TelephonyRegistryManager {
pkgName, attributionTag, callback, new int[0], notifyNow);
}
+ @NonNull
+ @GuardedBy("sSatelliteStateChangeListeners")
+ private static final Map<SatelliteStateChangeListener,
+ WeakReference<SatelliteStateChangeListenerWrapper>>
+ sSatelliteStateChangeListeners = new ArrayMap<>();
+
+ /**
+ * Register a {@link SatelliteStateChangeListener} to receive notification when Satellite state
+ * has changed.
+ *
+ * @param executor The {@link Executor} where the {@code listener} will be invoked
+ * @param listener The listener to monitor the satellite state change
+ * @hide
+ */
+ public void addSatelliteStateChangeListener(@NonNull @CallbackExecutor Executor executor,
+ @NonNull SatelliteStateChangeListener listener) {
+ if (listener == null || executor == null) {
+ throw new IllegalArgumentException("Listener and executor must be non-null");
+ }
+
+ synchronized (sSatelliteStateChangeListeners) {
+ WeakReference<SatelliteStateChangeListenerWrapper> existing =
+ sSatelliteStateChangeListeners.get(listener);
+ if (existing != null && existing.get() != null) {
+ Log.d(TAG, "addSatelliteStateChangeListener: listener already registered");
+ return;
+ }
+ SatelliteStateChangeListenerWrapper wrapper =
+ new SatelliteStateChangeListenerWrapper(executor, listener);
+ try {
+ sRegistry.addSatelliteStateChangeListener(
+ wrapper,
+ mContext.getOpPackageName(),
+ mContext.getAttributionTag());
+ sSatelliteStateChangeListeners.put(listener, new WeakReference<>(wrapper));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Unregister a {@link SatelliteStateChangeListener} to stop receiving notification when
+ * satellite state has changed.
+ *
+ * @param listener The listener previously registered with addSatelliteStateChangeListener.
+ * @hide
+ */
+ public void removeSatelliteStateChangeListener(@NonNull SatelliteStateChangeListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener must be non-null");
+ }
+
+ synchronized (sSatelliteStateChangeListeners) {
+ WeakReference<SatelliteStateChangeListenerWrapper> ref =
+ sSatelliteStateChangeListeners.get(listener);
+ if (ref == null) return;
+ SatelliteStateChangeListenerWrapper wrapper = ref.get();
+ if (wrapper == null) return;
+ try {
+ sRegistry.removeSatelliteStateChangeListener(wrapper, mContext.getOpPackageName());
+ sSatelliteStateChangeListeners.remove(listener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Notify the registrants that the satellite state has changed.
+ *
+ * @param isEnabled True if the satellite modem is enabled, false otherwise
+ * @hide
+ */
+ public void notifySatelliteStateChanged(boolean isEnabled) {
+ try {
+ sRegistry.notifySatelliteStateChanged(isEnabled);
+ } catch (RemoteException ex) {
+ // system process is dead
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ private static class SatelliteStateChangeListenerWrapper extends
+ ISatelliteStateChangeListener.Stub implements ListenerExecutor {
+ @NonNull private final WeakReference<SatelliteStateChangeListener> mListener;
+ @NonNull private final Executor mExecutor;
+
+ SatelliteStateChangeListenerWrapper(@NonNull Executor executor,
+ @NonNull SatelliteStateChangeListener listener) {
+ mExecutor = executor;
+ mListener = new WeakReference<>(listener);
+ }
+
+ @Override
+ public void onSatelliteEnabledStateChanged(boolean isEnabled) {
+ Binder.withCleanCallingIdentity(
+ () ->
+ executeSafely(
+ mExecutor,
+ mListener::get,
+ sscl -> sscl.onEnabledStateChanged(isEnabled)));
+ }
+ }
+
private static class CarrierPrivilegesCallbackWrapper extends ICarrierPrivilegesCallback.Stub
implements ListenerExecutor {
@NonNull private final WeakReference<CarrierPrivilegesCallback> mCallback;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d9092ee737ce..6090b5ec1622 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -30,7 +30,9 @@ import static android.view.Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
import static android.view.Surface.FRAME_RATE_COMPATIBILITY_GTE;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED;
+import static android.view.accessibility.Flags.FLAG_SUPPLEMENTAL_DESCRIPTION;
import static android.view.accessibility.Flags.removeChildHoverCheckForTouchExploration;
+import static android.view.accessibility.Flags.supplementalDescription;
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_BOUNDS;
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW;
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN;
@@ -4864,6 +4866,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private CharSequence mContentDescription;
/**
+ * Brief supplemental information for view and is primarily used for accessibility support.
+ */
+ private CharSequence mSupplementalDescription;
+
+ /**
* If this view represents a distinct part of the window, it can have a title that labels the
* area.
*/
@@ -6534,6 +6541,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
case R.styleable.View_contentSensitivity:
setContentSensitivity(a.getInt(attr, CONTENT_SENSITIVITY_AUTO));
break;
+ default: {
+ if (supplementalDescription()) {
+ if (attr == com.android.internal.R.styleable.View_supplementalDescription) {
+ setSupplementalDescription(a.getString(attr));
+ }
+ }
+ }
}
}
@@ -11806,6 +11820,39 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Returns the {@link View}'s supplemental description.
+ * <p>
+ * A supplemental description provides
+ * brief supplemental information for this node, such as the purpose of the node when
+ * that purpose is not conveyed within its textual representation. For example, if a
+ * dropdown select has a purpose of setting font family, the supplemental description
+ * could be "font family". If this node has children, its supplemental description serves
+ * as additional information and is not intended to replace any existing information
+ * in the subtree. This is different from the {@link #getContentDescription()} in that
+ * this description is purely supplemental while a content description may be used
+ * to replace a description for a node or its subtree that an assistive technology
+ * would otherwise compute based on other properties of the node and its descendants.
+ *
+ * <p>
+ * <strong>Note:</strong> Do not override this method, as it will have no
+ * effect on the supplemental description presented to accessibility services.
+ * You must call {@link #setSupplementalDescription(CharSequence)} to modify the
+ * supplemental description.
+ *
+ * @return the supplemental description
+ * @see #setSupplementalDescription(CharSequence)
+ * @see #getContentDescription()
+ * @attr ref android.R.styleable#View_supplementalDescription
+ */
+ @FlaggedApi(FLAG_SUPPLEMENTAL_DESCRIPTION)
+ @ViewDebug.ExportedProperty(category = "accessibility")
+ @InspectableProperty
+ @Nullable
+ public CharSequence getSupplementalDescription() {
+ return mSupplementalDescription;
+ }
+
+ /**
* Sets the {@link View}'s state description.
* <p>
* A state description briefly describes the states of the view and is primarily used
@@ -11892,6 +11939,53 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Sets the {@link View}'s supplemental description.
+ * <p>
+ * A supplemental description provides
+ * brief supplemental information for this node, such as the purpose of the node when
+ * that purpose is not conveyed within its textual representation. For example, if a
+ * dropdown select has a purpose of setting font family, the supplemental description
+ * could be "font family". If this node has children, its supplemental description serves
+ * as additional information and is not intended to replace any existing information
+ * in the subtree. This is different from the {@link #setContentDescription(CharSequence)}
+ * in that this description is purely supplemental while a content description may be used
+ * to replace a description for a node or its subtree that an assistive technology
+ * would otherwise compute based on other properties of the node and its descendants.
+ *
+ * <p>
+ * This should omit role or state. Role refers to the kind of user-interface element the View
+ * is, such as a Button or Checkbox. State refers to a frequently changing property of the View,
+ * such as an On/Off state of a button or the audio level of a volume slider.
+ *
+ * @param supplementalDescription The supplemental description.
+ * @see #getSupplementalDescription()
+ * @see #setContentDescription(CharSequence)
+ * @see #setStateDescription(CharSequence) for state changes.
+ * @attr ref android.R.styleable#View_supplementalDescription
+ */
+ @FlaggedApi(FLAG_SUPPLEMENTAL_DESCRIPTION)
+ @RemotableViewMethod
+ public void setSupplementalDescription(@Nullable CharSequence supplementalDescription) {
+ if (mSupplementalDescription == null) {
+ if (supplementalDescription == null) {
+ return;
+ }
+ } else if (mSupplementalDescription.equals(supplementalDescription)) {
+ return;
+ }
+ mSupplementalDescription = supplementalDescription;
+ final boolean nonEmptyDesc = supplementalDescription != null
+ && !supplementalDescription.isEmpty();
+ if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+ setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+ notifySubtreeAccessibilityStateChangedIfNeeded();
+ } else {
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_SUPPLEMENTAL_DESCRIPTION);
+ }
+ }
+
+ /**
* Sets the id of a view that screen readers are requested to visit after this view.
*
* <p>
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 4e9d054dae07..c690787e4a33 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -810,6 +810,20 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
@FlaggedApi(Flags.FLAG_A11Y_EXPANSION_STATE_API)
public static final int CONTENT_CHANGE_TYPE_EXPANDED = 1 << 14;
+ /**
+ * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
+ * The source node changed its supplemental description, which is returned by
+ * {@link AccessibilityNodeInfo#getSupplementalDescription()}.
+ * The view changing its supplemental description should call
+ * {@link AccessibilityNodeInfo#setSupplementalDescription(CharSequence)} and
+ * then send this event.
+ *
+ * @see AccessibilityNodeInfo#getSupplementalDescription()
+ * @see AccessibilityNodeInfo#setSupplementalDescription(CharSequence)
+ */
+ @FlaggedApi(Flags.FLAG_SUPPLEMENTAL_DESCRIPTION)
+ public static final int CONTENT_CHANGE_TYPE_SUPPLEMENTAL_DESCRIPTION = 1 << 15;
+
// Speech state change types.
/** Change type for {@link #TYPE_SPEECH_STATE_CHANGE} event: another service is speaking. */
@@ -942,6 +956,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
CONTENT_CHANGE_TYPE_CONTENT_INVALID,
CONTENT_CHANGE_TYPE_ERROR,
CONTENT_CHANGE_TYPE_ENABLED,
+ CONTENT_CHANGE_TYPE_SUPPLEMENTAL_DESCRIPTION,
})
public @interface ContentChangeTypes {}
@@ -1222,7 +1237,14 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
return "CONTENT_CHANGE_TYPE_CONTENT_INVALID";
case CONTENT_CHANGE_TYPE_ERROR: return "CONTENT_CHANGE_TYPE_ERROR";
case CONTENT_CHANGE_TYPE_ENABLED: return "CONTENT_CHANGE_TYPE_ENABLED";
- default: return Integer.toHexString(type);
+ default: {
+ if (Flags.supplementalDescription()) {
+ if (type == CONTENT_CHANGE_TYPE_SUPPLEMENTAL_DESCRIPTION) {
+ return "CONTENT_CHANGE_TYPE_SUPPLEMENTAL_DESCRIPTION";
+ }
+ }
+ return Integer.toHexString(type);
+ }
}
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index f70f7e6a59c0..e7acfdf7b26e 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -1085,6 +1085,7 @@ public class AccessibilityNodeInfo implements Parcelable {
private CharSequence mPaneTitle;
private CharSequence mStateDescription;
private CharSequence mContentDescription;
+ private CharSequence mSupplementalDescription;
private CharSequence mTooltipText;
private String mViewIdResourceName;
private String mUniqueId;
@@ -3686,6 +3687,27 @@ public class AccessibilityNodeInfo implements Parcelable {
return mContentDescription;
}
+ /**
+ * Gets the supplemental description of this node. A supplemental description provides
+ * brief supplemental information for this node, such as the purpose of the node when
+ * that purpose is not conveyed within its textual representation. For example, if a
+ * dropdown select has a purpose of setting font family, the supplemental description
+ * could be "font family". If this node has children, its supplemental description serves
+ * as additional information and is not intended to replace any existing information
+ * in the subtree. This is different from the {@link #getContentDescription()} in that
+ * this description is purely supplemental while a content description may be used
+ * to replace a description for a node or its subtree that an assistive technology
+ * would otherwise compute based on other properties of the node and its descendants.
+ *
+ * @return The supplemental description.
+ * @see #setSupplementalDescription(CharSequence)
+ * @see #getContentDescription()
+ */
+ @FlaggedApi(Flags.FLAG_SUPPLEMENTAL_DESCRIPTION)
+ @Nullable
+ public CharSequence getSupplementalDescription() {
+ return mSupplementalDescription;
+ }
/**
* Sets the state description of this node.
@@ -3724,6 +3746,35 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
+ * Sets the supplemental description of this node. A supplemental description provides
+ * brief supplemental information for this node, such as the purpose of the node when
+ * that purpose is not conveyed within its textual representation. For example, if a
+ * dropdown select has a purpose of setting font family, the supplemental description
+ * could be "font family". If this node has children, its supplemental description serves
+ * as additional information and is not intended to replace any existing information
+ * in the subtree. This is different from the {@link #setContentDescription(CharSequence)}
+ * in that this description is purely supplemental while a content description may be used
+ * to replace a description for a node or its subtree that an assistive technology
+ * would otherwise compute based on other properties of the node and its descendants.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ *
+ * @param supplementalDescription The supplemental description.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ * @see #getSupplementalDescription()
+ * @see #setContentDescription(CharSequence)
+ */
+ @FlaggedApi(Flags.FLAG_SUPPLEMENTAL_DESCRIPTION)
+ public void setSupplementalDescription(@Nullable CharSequence supplementalDescription) {
+ enforceNotSealed();
+ mSupplementalDescription = (supplementalDescription == null) ? null
+ : supplementalDescription.subSequence(0, supplementalDescription.length());
+ }
+
+ /**
* Gets the tooltip text of this node.
*
* @return The tooltip text.
@@ -4657,6 +4708,10 @@ public class AccessibilityNodeInfo implements Parcelable {
nonDefaultFields |= bitAt(fieldIndex);
}
fieldIndex++;
+ if (!Objects.equals(mSupplementalDescription, DEFAULT.mSupplementalDescription)) {
+ nonDefaultFields |= bitAt(fieldIndex);
+ }
+ fieldIndex++;
if (!Objects.equals(mPaneTitle, DEFAULT.mPaneTitle)) {
nonDefaultFields |= bitAt(fieldIndex);
}
@@ -4843,6 +4898,9 @@ public class AccessibilityNodeInfo implements Parcelable {
if (isBitSet(nonDefaultFields, fieldIndex++)) {
parcel.writeCharSequence(mContentDescription);
}
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ parcel.writeCharSequence(mSupplementalDescription);
+ }
if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mPaneTitle);
if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mTooltipText);
if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mContainerTitle);
@@ -4950,6 +5008,7 @@ public class AccessibilityNodeInfo implements Parcelable {
mError = other.mError;
mStateDescription = other.mStateDescription;
mContentDescription = other.mContentDescription;
+ mSupplementalDescription = other.mSupplementalDescription;
mPaneTitle = other.mPaneTitle;
mTooltipText = other.mTooltipText;
mContainerTitle = other.mContainerTitle;
@@ -5119,6 +5178,9 @@ public class AccessibilityNodeInfo implements Parcelable {
if (isBitSet(nonDefaultFields, fieldIndex++)) {
mContentDescription = parcel.readCharSequence();
}
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ mSupplementalDescription = parcel.readCharSequence();
+ }
if (isBitSet(nonDefaultFields, fieldIndex++)) mPaneTitle = parcel.readCharSequence();
if (isBitSet(nonDefaultFields, fieldIndex++)) mTooltipText = parcel.readCharSequence();
if (isBitSet(nonDefaultFields, fieldIndex++)) mContainerTitle = parcel.readCharSequence();
@@ -5483,6 +5545,9 @@ public class AccessibilityNodeInfo implements Parcelable {
builder.append("; maxTextLength: ").append(mMaxTextLength);
builder.append("; stateDescription: ").append(mStateDescription);
builder.append("; contentDescription: ").append(mContentDescription);
+ if (Flags.supplementalDescription()) {
+ builder.append("; supplementalDescription: ").append(mSupplementalDescription);
+ }
builder.append("; tooltipText: ").append(mTooltipText);
builder.append("; containerTitle: ").append(mContainerTitle);
builder.append("; viewIdResName: ").append(mViewIdResourceName);
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index ffa819f1f183..fde42af85420 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -222,6 +222,13 @@ flag {
}
flag {
+ name: "supplemental_description"
+ namespace: "accessibility"
+ description: "Feature flag for supplemental description api"
+ bug: "375266174"
+}
+
+flag {
name: "support_multiple_labeledby"
namespace: "accessibility"
description: "Feature flag for supporting multiple labels in AccessibilityNodeInfo labeledby api"
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 34abf3114925..3fe63ab17248 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -1867,27 +1867,33 @@ public final class WindowContainerTransaction implements Parcelable {
switch (type) {
case HIERARCHY_OP_TYPE_REPARENT: return "reparent";
case HIERARCHY_OP_TYPE_REORDER: return "reorder";
- case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: return "ChildrenTasksReparent";
- case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: return "SetLaunchRoot";
- case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS: return "SetAdjacentRoot";
- case HIERARCHY_OP_TYPE_LAUNCH_TASK: return "LaunchTask";
- case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: return "SetAdjacentFlagRoot";
+ case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: return "childrenTasksReparent";
+ case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: return "setLaunchRoot";
+ case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS: return "setAdjacentRoot";
+ case HIERARCHY_OP_TYPE_LAUNCH_TASK: return "launchTask";
+ case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: return "setAdjacentFlagRoot";
case HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT:
- return "SetDisableLaunchAdjacent";
- case HIERARCHY_OP_TYPE_PENDING_INTENT: return "PendingIntent";
- case HIERARCHY_OP_TYPE_START_SHORTCUT: return "StartShortcut";
+ return "setDisableLaunchAdjacent";
+ case HIERARCHY_OP_TYPE_PENDING_INTENT: return "pendingIntent";
+ case HIERARCHY_OP_TYPE_START_SHORTCUT: return "startShortcut";
+ case HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER: return "restoreTransientOrder";
case HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER: return "addInsetsFrameProvider";
case HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER:
return "removeInsetsFrameProvider";
case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP: return "setAlwaysOnTop";
- case HIERARCHY_OP_TYPE_REMOVE_TASK: return "RemoveTask";
+ case HIERARCHY_OP_TYPE_REMOVE_TASK: return "removeTask";
case HIERARCHY_OP_TYPE_FINISH_ACTIVITY: return "finishActivity";
- case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS: return "ClearAdjacentRoot";
+ case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS: return "clearAdjacentRoot";
case HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH:
return "setReparentLeafTaskIfRelaunch";
case HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION:
return "addTaskFragmentOperation";
+ case HIERARCHY_OP_TYPE_MOVE_PIP_ACTIVITY_TO_PINNED_TASK:
+ return "movePipActivityToPinnedTask";
+ case HIERARCHY_OP_TYPE_SET_IS_TRIMMABLE: return "setIsTrimmable";
+ case HIERARCHY_OP_TYPE_RESTORE_BACK_NAVIGATION: return "restoreBackNav";
case HIERARCHY_OP_TYPE_SET_EXCLUDE_INSETS_TYPES: return "setExcludeInsetsTypes";
+ case HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE: return "setKeyguardState";
default: return "HOP(" + type + ")";
}
}
diff --git a/core/java/com/android/internal/telephony/ISatelliteStateChangeListener.aidl b/core/java/com/android/internal/telephony/ISatelliteStateChangeListener.aidl
new file mode 100644
index 000000000000..4d195c2028b5
--- /dev/null
+++ b/core/java/com/android/internal/telephony/ISatelliteStateChangeListener.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+oneway interface ISatelliteStateChangeListener {
+ void onSatelliteEnabledStateChanged(boolean isEnabled);
+} \ No newline at end of file
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index ca75abdedfcc..1c76a6cd4bba 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -38,6 +38,7 @@ import com.android.internal.telephony.ICarrierConfigChangeListener;
import com.android.internal.telephony.ICarrierPrivilegesCallback;
import com.android.internal.telephony.IPhoneStateListener;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
+import com.android.internal.telephony.ISatelliteStateChangeListener;
interface ITelephonyRegistry {
void addOnSubscriptionsChangedListener(String pkg, String featureId,
@@ -124,4 +125,8 @@ interface ITelephonyRegistry {
void notifyCarrierRoamingNtnModeChanged(int subId, in boolean active);
void notifyCarrierRoamingNtnEligibleStateChanged(int subId, in boolean eligible);
void notifyCarrierRoamingNtnAvailableServicesChanged(int subId, in int[] availableServices);
+
+ void addSatelliteStateChangeListener(ISatelliteStateChangeListener listener, String pkg, String featureId);
+ void removeSatelliteStateChangeListener(ISatelliteStateChangeListener listener, String pkg);
+ void notifySatelliteStateChanged(boolean isEnabled);
}
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index ef420eb0a35a..3fac7360c8f2 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1943,8 +1943,7 @@
<string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Off"</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>
- <!-- no translation found for zen_mode_trigger_summary_range_words (7228261413029290750) -->
- <skip />
+ <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"<xliff:g id="START">%1$s</xliff:g> to <xliff:g id="END">%2$s</xliff:g>"</string>
<string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Any calendar"</string>
<string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> is muting some sounds"</string>
<string name="system_error_wipe_data" msgid="5910572292172208493">"There\'s an internal problem with your device, and it may be unstable until you factory data reset."</string>
@@ -2426,14 +2425,10 @@
<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>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"How it works"</string>
- <!-- no translation found for satellite_manual_selection_state_popup_title (8545991934926661974) -->
- <skip />
- <!-- no translation found for satellite_manual_selection_state_popup_message (1928101658551382450) -->
- <skip />
- <!-- no translation found for satellite_manual_selection_state_popup_ok (2459664752624985095) -->
- <skip />
- <!-- no translation found for satellite_manual_selection_state_popup_cancel (973605633339469252) -->
- <skip />
+ <string name="satellite_manual_selection_state_popup_title" msgid="8545991934926661974">"Turn on \"Automatically select network\""</string>
+ <string name="satellite_manual_selection_state_popup_message" msgid="1928101658551382450">"Turn on \"Automatically select network\" in Settings so your phone can find a network that works with satellite"</string>
+ <string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Turn on"</string>
+ <string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Go back"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pending..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Set up Fingerprint Unlock again"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> can no longer be recognized."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 051c61a26373..4070f1160aec 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1944,8 +1944,7 @@
<string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Off"</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>
- <!-- no translation found for zen_mode_trigger_summary_range_words (7228261413029290750) -->
- <skip />
+ <string name="zen_mode_trigger_summary_range_words" msgid="7228261413029290750">"Da <xliff:g id="START">%1$s</xliff:g> a <xliff:g id="END">%2$s</xliff:g>"</string>
<string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Qualsiasi calendario"</string>
<string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> sta disattivando alcuni suoni"</string>
<string name="system_error_wipe_data" msgid="5910572292172208493">"Si è verificato un problema interno con il dispositivo, che potrebbe essere instabile fino al ripristino dei dati di fabbrica."</string>
@@ -2427,14 +2426,10 @@
<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>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Come funziona"</string>
- <!-- no translation found for satellite_manual_selection_state_popup_title (8545991934926661974) -->
- <skip />
- <!-- no translation found for satellite_manual_selection_state_popup_message (1928101658551382450) -->
- <skip />
- <!-- no translation found for satellite_manual_selection_state_popup_ok (2459664752624985095) -->
- <skip />
- <!-- no translation found for satellite_manual_selection_state_popup_cancel (973605633339469252) -->
- <skip />
+ <string name="satellite_manual_selection_state_popup_title" msgid="8545991934926661974">"Attiva \"Seleziona rete automaticamente\""</string>
+ <string name="satellite_manual_selection_state_popup_message" msgid="1928101658551382450">"Attiva \"Seleziona rete automaticamente\" nelle Impostazioni in modo che lo smartphone possa trovare una rete compatibile con il satellite"</string>
+ <string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Attiva"</string>
+ <string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Indietro"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"In attesa…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Riconfigura lo Sblocco con l\'Impronta"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"<xliff:g id="FINGERPRINT">%s</xliff:g> non può più essere riconosciuto."</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 2fea96252ebc..5684d780be8f 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -590,7 +590,7 @@
<string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"तपाईँको फोन मात्र होइन, मल्टिकास्ट ठेगानाहरूको प्रयोग गरे Wi-Fi नेटवर्कका सबै उपकरणहरूमा पठाइएका प्याकेटहरू प्राप्त गर्न एपलाई अनुमति दिन्छ। यसले गैर-मल्टिकास्ट मोडभन्दा बढी उर्जा प्रयोग गर्छ।"</string>
<string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"ब्लुटुथ सेटिङहरूमा पहुँच गर्नुहोस्"</string>
<string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"स्थानीय ब्लुटुथ ट्याब्लेटलाई कन्फिगर गर्नको लागि र टाढाका उपकरणहरूलाई पत्ता लगाउन र जोड्नको लागि एपलाई अनुमति दिन्छ।"</string>
- <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"एपलाई तपाईंको Android टिभी डिभाइसको ब्लुटुथ कन्फिगर गर्ने तथा टाढा रहेका यन्त्रहरू पत्ता लगाई ती यन्त्रहरूसँग जोडा बनाउने अनुमति दिन्छ।"</string>
+ <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"एपलाई तपाईंको Android टिभी डिभाइसको ब्लुटुथ कन्फिगर गर्ने तथा टाढा रहेका यन्त्रहरू पत्ता लगाई ती यन्त्रहरूसँग कनेक्ट गर्ने अनुमति दिन्छ।"</string>
<string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"एपलाई स्थानीय ब्लुटुथ फोन कन्फिगर गर्न र टाढाका उपकरणहरूसँग खोज गर्न र जोडी गर्न अनुमति दिन्छ।"</string>
<string name="permlab_accessWimaxState" msgid="7029563339012437434">"WiMAXसँग जोड्नुहोस् वा छुटाउनुहोस्"</string>
<string name="permdesc_accessWimaxState" msgid="5372734776802067708">"एपलाई वाइम्याक्स सक्षम छ कि छैन र जडान भएको कुनै पनि वाइम्याक्स नेटवर्कहरूको बारेमा जानकारी निर्धारिण गर्न अनुमति दिन्छ।"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 388c5a9077ae..86e0fcdad8a1 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1944,8 +1944,7 @@
<string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Desativada"</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>
- <!-- no translation found for zen_mode_trigger_summary_range_words (7228261413029290750) -->
- <skip />
+ <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_event_calendar_any" msgid="2086784607921121803">"Qualquer calendário"</string>
<string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> está a desativar alguns sons."</string>
<string name="system_error_wipe_data" msgid="5910572292172208493">"Existe um problema interno no seu dispositivo e pode ficar instável até efetuar uma reposição de dados de fábrica."</string>
@@ -2427,14 +2426,10 @@
<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>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Como funciona"</string>
- <!-- no translation found for satellite_manual_selection_state_popup_title (8545991934926661974) -->
- <skip />
- <!-- no translation found for satellite_manual_selection_state_popup_message (1928101658551382450) -->
- <skip />
- <!-- no translation found for satellite_manual_selection_state_popup_ok (2459664752624985095) -->
- <skip />
- <!-- no translation found for satellite_manual_selection_state_popup_cancel (973605633339469252) -->
- <skip />
+ <string name="satellite_manual_selection_state_popup_title" msgid="8545991934926661974">"Ative a opção \"Selecionar rede automaticamente\""</string>
+ <string name="satellite_manual_selection_state_popup_message" msgid="1928101658551382450">"Ative a opção \"Selecionar rede automaticamente\" nas Definições para que o telemóvel possa encontrar uma rede que funcione com o satélite"</string>
+ <string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Ativar"</string>
+ <string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Retroceder"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendente…"</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Configure o Desbloqueio por impressão digital novamente"</string>
<string name="fingerprint_dangling_notification_msg_1" msgid="5851784577768803510">"Já não é possível reconhecer <xliff:g id="FINGERPRINT">%s</xliff:g>."</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 492dca723c21..1d9e00c012bb 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1937,7 +1937,7 @@
<string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"వారపు రోజుల్లో రాత్రి"</string>
<string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"వారాంతం"</string>
<string name="zen_mode_default_events_name" msgid="2280682960128512257">"ఈవెంట్"</string>
- <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"నిద్ర"</string>
+ <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"స్లీప్ మోడ్"</string>
<string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> ద్వారా మేనేజ్ చేయబడుతోంది"</string>
<string name="zen_mode_implicit_activated" msgid="2634285680776672994">"ఆన్‌లో ఉంది"</string>
<string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"ఆఫ్‌లో ఉంది"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d750ff6623f2..4c9da6959fe2 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3486,6 +3486,12 @@
representation this attribute can be used for providing such. -->
<attr name="contentDescription" format="string" localization="suggested" />
+ <!-- Provides brief supplemental information for the view, such as the purpose of
+ the view when that purpose is not conveyed within its textual representation.
+ This property is used primarily for accessibility. -->
+ <!-- @FlaggedApi("android.view.accessibility.supplemental_description") -->
+ <attr name="supplementalDescription" format="string" localization="suggested" />
+
<!-- Sets the id of a view that screen readers are requested to visit after this view.
Requests that a screen-reader visits the content of this view before the content of the
one it precedes. This does nothing if either view is not important for accessibility.
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index 81215453b3ef..09dc08420a01 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -121,6 +121,8 @@
<!-- @FlaggedApi("android.permission.flags.replace_body_sensor_permission_enabled")
@hide @SystemApi -->
<public name="backgroundPermission"/>
+ <!-- @FlaggedApi(android.view.accessibility.supplemental_description) -->
+ <public name="supplementalDescription"/>
</staging-public-group>
<staging-public-group type="id" first-id="0x01b60000">
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
index 930e03dfd6db..bef65d42ba79 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
@@ -46,7 +46,7 @@ public class AccessibilityNodeInfoTest {
// The number of fields tested in the corresponding CTS AccessibilityNodeInfoTest:
// See fullyPopulateAccessibilityNodeInfo, assertEqualsAccessibilityNodeInfo,
// and assertAccessibilityNodeInfoCleared in that class.
- private static final int NUM_MARSHALLED_PROPERTIES = 46;
+ private static final int NUM_MARSHALLED_PROPERTIES = 47;
/**
* The number of properties that are purposely not marshalled
diff --git a/core/tests/vibrator/src/android/os/VibrationEffectTest.java b/core/tests/vibrator/src/android/os/VibrationEffectTest.java
index beb69858a85c..1cd1190c4080 100644
--- a/core/tests/vibrator/src/android/os/VibrationEffectTest.java
+++ b/core/tests/vibrator/src/android/os/VibrationEffectTest.java
@@ -425,6 +425,15 @@ public class VibrationEffectTest {
.build();
assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
+
+ effect = VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 60)
+ .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20)
+ .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 50)
+ .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 80)
+ .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 40)
+ .build();
+
+ assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
}
@Test
@@ -643,6 +652,14 @@ public class VibrationEffectTest {
.build()
.validate();
+ VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 30)
+ .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20)
+ .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 50)
+ .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 80)
+ .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 40)
+ .build()
+ .validate();
+
VibrationEffect.createRepeatingEffect(
/*preamble=*/ VibrationEffect.startWaveformEnvelope()
.addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f,
@@ -693,6 +710,34 @@ public class VibrationEffectTest {
/*timeMillis=*/ 0)
.build()
.validate());
+
+ assertThrows(IllegalStateException.class,
+ () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30)
+ .build().validate());
+ assertThrows(IllegalArgumentException.class,
+ () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30)
+ .addControlPoint(/*amplitude=*/ -1.0f, /*frequencyHz=*/ 60f,
+ /*timeMillis=*/ 20)
+ .build()
+ .validate());
+ assertThrows(IllegalArgumentException.class,
+ () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30)
+ .addControlPoint(/*amplitude=*/ 1.1f, /*frequencyHz=*/ 60f,
+ /*timeMillis=*/ 20)
+ .build()
+ .validate());
+ assertThrows(IllegalArgumentException.class,
+ () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30)
+ .addControlPoint(/*amplitude=*/ 0.8f, /*frequencyHz=*/ 0f,
+ /*timeMillis=*/ 20)
+ .build()
+ .validate());
+ assertThrows(IllegalArgumentException.class,
+ () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30)
+ .addControlPoint(/*amplitude=*/ 0.8f, /*frequencyHz=*/ 100f,
+ /*timeMillis=*/ 0)
+ .build()
+ .validate());
}
@Test
@@ -1331,6 +1376,11 @@ public class VibrationEffectTest {
.addTransition(Duration.ofMillis(500), targetAmplitude(0))
.build()
.isHapticFeedbackCandidate());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+ public void testIsHapticFeedbackCandidate_longEnvelopeEffects_notCandidates() {
assertFalse(VibrationEffect.startWaveformEnvelope()
.addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 200)
.addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 500)
@@ -1338,6 +1388,13 @@ public class VibrationEffectTest {
.addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 400)
.build()
.isHapticFeedbackCandidate());
+ assertFalse(VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 40)
+ .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 200)
+ .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 500)
+ .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 800)
+ .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 400)
+ .build()
+ .isHapticFeedbackCandidate());
}
@Test
@@ -1351,12 +1408,23 @@ public class VibrationEffectTest {
.addTransition(Duration.ofMillis(300), targetAmplitude(0))
.build()
.isHapticFeedbackCandidate());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+ public void testIsHapticFeedbackCandidate_shortEnvelopeEffects_areCandidates() {
assertTrue(VibrationEffect.startWaveformEnvelope()
.addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 500)
.addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 400)
.addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 100)
.build()
.isHapticFeedbackCandidate());
+ assertTrue(VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 30)
+ .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 500)
+ .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 400)
+ .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 100)
+ .build()
+ .isHapticFeedbackCandidate());
}
@Test
diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
index 82b3f6875d67..71baed8219d5 100644
--- a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
@@ -37,6 +37,7 @@ import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
+import com.android.graphics.hwui.flags.Flags;
import com.android.internal.R;
import dalvik.annotation.optimization.FastNative;
@@ -525,6 +526,35 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 {
}
}
+ @Override
+ public void setFilterBitmap(boolean filterBitmap) {
+ if (!Flags.animatedImageDrawableFilterBitmap()) {
+ super.setFilterBitmap(filterBitmap);
+ return;
+ }
+ if (mState.mNativePtr == 0) {
+ throw new IllegalStateException(
+ "called setFilterBitmap on empty AnimatedImageDrawable"
+ );
+ }
+ if (nSetFilterBitmap(mState.mNativePtr, filterBitmap)) {
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ public boolean isFilterBitmap() {
+ if (!Flags.animatedImageDrawableFilterBitmap()) {
+ return super.isFilterBitmap();
+ }
+ if (mState.mNativePtr == 0) {
+ throw new IllegalStateException(
+ "called isFilterBitmap on empty AnimatedImageDrawable"
+ );
+ }
+ return nGetFilterBitmap(mState.mNativePtr);
+ }
+
private void postOnAnimationStart() {
if (mAnimationCallbacks == null) {
return;
@@ -618,4 +648,8 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 {
private static native void nSetMirrored(long nativePtr, boolean mirror);
@FastNative
private static native void nSetBounds(long nativePtr, Rect rect);
+ @FastNative
+ private static native boolean nSetFilterBitmap(long nativePtr, boolean filterBitmap);
+ @FastNative
+ private static native boolean nGetFilterBitmap(long nativePtr);
}
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index c36783f8f488..a8febc80ffc1 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"تكبير الشاشة إلى أقصى حدّ"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"التقاط صورة للشاشة"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"لا يمكن نقل التطبيق إلى هنا"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"مجسَّم"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"استعادة"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"تكبير"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"استعادة"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"المحاذاة إلى اليسار"</string>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index 71d95edccea6..8c924e342875 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"স্ক্ৰীন মেক্সিমাইজ কৰক"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"স্ক্ৰীন স্নেপ কৰক"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ইয়ালৈ এপ্‌টো আনিব নোৱাৰি"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ইমাৰ্ছিভ"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"পুনঃস্থাপন কৰক"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"মেক্সিমাইজ কৰক"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"পুনঃস্থাপন কৰক"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"বাওঁফাললৈ স্নেপ কৰক"</string>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index 4412497c3862..22a445f1754c 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"স্ক্রিন বড় করুন"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"স্ক্রিনে অ্যাপ মানানসই হিসেবে ছোট বড় করুন"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"অ্যাপটি এখানে সরানো যাবে না"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ইমারসিভ"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ফিরিয়ে আনুন"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"বড় করুন"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"ফিরিয়ে আনুন"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"বাঁদিকে স্ন্যাপ করুন"</string>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index 674022be39a2..73f30d797883 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimiziraj ekran"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snimi ekran"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ne možete premjestiti aplikaciju ovdje"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Interaktivno"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Vrati"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimiziranje"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Vraćanje"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Pomicanje ulijevo"</string>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index fc6b679a3a09..6a5780e01822 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximalizovat obrazovku"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Rozpůlit obrazovku"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikaci sem nelze přesunout"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Pohlcující"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Obnovit"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximalizovat"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Obnovit"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Přichytit vlevo"</string>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index d06b46fb40d4..d02fae2a986d 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Μεγιστοποίηση οθόνης"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Προβολή στο μισό της οθόνης"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Δεν είναι δυνατή η μετακίνηση της εφαρμογής εδώ"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Καθηλωτικό"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Επαναφορά"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Μεγιστοποίηση"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Επαναφορά"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Κούμπωμα αριστερά"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index c1a4244896c5..f9911451f4b5 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap screen"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersive"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restore"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximise"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restore"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Snap left"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index c1a4244896c5..f9911451f4b5 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap screen"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersive"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restore"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximise"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restore"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Snap left"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index c1a4244896c5..f9911451f4b5 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap screen"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersive"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restore"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximise"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restore"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Snap left"</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index ff675a9f6356..527793eac9c3 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रीन को बड़ा करें"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"स्नैप स्क्रीन"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ऐप्लिकेशन को यहां मूव नहीं किया जा सकता"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"इमर्सिव"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"वापस लाएं"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"बड़ा करें"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"पहले जैसा करें"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"बाईं ओर स्नैप करें"</string>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index 16fbcd0565fa..659d1ec39b73 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimalno povećaj zaslon"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Izradi snimku zaslona"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacija se ne može premjestiti ovdje"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Interaktivno"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Vrati"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimiziraj"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Vrati"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Poravnaj lijevo"</string>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index f595765a797e..ca1bc15edf33 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Stækka skjá"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Smelluskjár"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ekki er hægt að færa forritið hingað"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Umlykjandi"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Endurheimta"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Stækka"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Endurheimta"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Smella til vinstri"</string>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index 8b7c15ffeb15..87919b5dc1ff 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Massimizza schermo"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Aggancia schermo"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Impossibile spostare l\'app qui"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersivo"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Ripristina"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Ingrandisci"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Ripristina"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Aggancia a sinistra"</string>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index 5464cfa28b3c..c7a77d9b9214 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"画面の最大化"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"画面のスナップ"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"アプリはここに移動できません"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"没入モード"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"復元"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"最大化"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"復元"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"左にスナップ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index 7ea9daffca18..39362ef4ca57 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"აპლიკაციის გაშლა სრულ ეკრანზე"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"აპლიკაციის დაპატარავება ეკრანზე"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"აპის აქ გადატანა შეუძლებელია"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"იმერსიული"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"აღდგენა"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"მაქსიმალურად გაშლა"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"აღდგენა"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"მარცხნივ გადატანა"</string>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index 83bd3744d27a..9c4ae05f3a36 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ពង្រីកអេក្រង់"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ថតអេក្រង់"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"មិនអាចផ្លាស់ទីកម្មវិធីមកទីនេះបានទេ"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ជក់ចិត្ត"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ស្ដារ"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"ពង្រីក"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"ស្ដារ"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ផ្លាស់ទីទៅឆ្វេង"</string>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index 502e0c92f844..f365cfb34412 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ಸ್ಕ್ರೀನ್ ಅನ್ನು ಮ್ಯಾಕ್ಸಿಮೈಸ್ ಮಾಡಿ"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ಸ್ನ್ಯಾಪ್ ಸ್ಕ್ರೀನ್"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ಆ್ಯಪ್ ಅನ್ನು ಇಲ್ಲಿಗೆ ಸರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ಇಮ್ಮರ್ಸಿವ್"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ಮರುಸ್ಥಾಪಿಸಿ"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"ಮ್ಯಾಕ್ಸಿಮೈಸ್ ಮಾಡಿ"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"ಮರುಸ್ಥಾಪಿಸಿ"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ಎಡಕ್ಕೆ ಸ್ನ್ಯಾಪ್ ಮಾಡಿ"</string>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index 4551f72eb635..5a7f58e5781a 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Išskleisti ekraną"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Sutraukti ekraną"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Programos negalima perkelti čia"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Įtraukiantis"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Atkurti"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Padidinti"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Atkurti"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Pritraukti kairėje"</string>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index a2c610e82823..871bc3fcc8e7 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रीन मोठी करा"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"स्क्रीन स्नॅप करा"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"अ‍ॅप इथे हलवू शकत नाही"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"इमर्सिव्ह"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"रिस्टोअर करा"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"मोठे करा"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"रिस्टोअर करा"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"डावीकडे स्नॅप करा"</string>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index 2102a382d232..71666cae93c8 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimumkan Skrin"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Tangkap Skrin"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Apl tidak boleh dialihkan ke sini"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Mengasyikkan"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Pulihkan"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimumkan"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Pulihkan"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Autojajar ke kiri"</string>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index e9a530621c7e..7015b2c11b32 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रिन ठुलो बनाउनुहोस्"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"स्क्रिन स्न्याप गर्नुहोस्"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"एप सारेर यहाँ ल्याउन सकिएन"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"इमर्सिभ"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"रिस्टोर गर्नुहोस्"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"ठुलो बनाउनुहोस्"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"रिस्टोर गर्नुहोस्"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"बायाँतिर स्न्याप गर्नुहोस्"</string>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index 14b7a09f6143..5f78b134ad22 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksymalizuj ekran"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Przyciągnij ekran"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Nie można przenieść aplikacji tutaj"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Tryb immersyjny"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Przywróć"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksymalizuj"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Przywróć"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Przyciągnij do lewej"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index 9631c45a8097..cd78ef95d88e 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar ecrã"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Encaixar ecrã"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Não é possível mover a app para aqui"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Envolvente"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restaurar"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximizar"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restaurar"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Encaixar à esquerda"</string>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index 2012c8a6754e..ae7e524da6cc 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimiraj zaslon"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Pripni zaslon"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacije ni mogoče premakniti sem"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Poglobljeno"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Obnovi"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimiraj"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Obnovi"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Pripni levo"</string>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index c4243f7ae90d..2c73d3a14620 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"திரையைப் பெரிதாக்கு"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"திரையை ஸ்னாப் செய்"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ஆப்ஸை இங்கே நகர்த்த முடியாது"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ஈடுபட வைக்கும்"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"மீட்டெடுக்கும்"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"பெரிதாக்கும்"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"மீட்டெடுக்கும்"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"இடதுபுறம் நகர்த்தும்"</string>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 47fc48ddc3c3..b17d4d1afaf7 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"స్క్రీన్ సైజ్‌ను పెంచండి"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"స్క్రీన్‌ను స్నాప్ చేయండి"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"యాప్‌ను ఇక్కడకి తరలించడం సాధ్యం కాదు"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"లీనమయ్యే"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"రీస్టోర్ చేయండి"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"మ్యాగ్జిమైజ్ చేయండి"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"రీస్టోర్ చేయండి"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ఎడమ వైపున స్నాప్ చేయండి"</string>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index 260807537385..43cee41f5a15 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ขยายหน้าจอให้ใหญ่สุด"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"สแนปหน้าจอ"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ย้ายแอปมาที่นี่ไม่ได้"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"สมจริง"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"คืนค่า"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"ขยายใหญ่สุด"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"คืนค่า"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"จัดพอดีกับทางซ้าย"</string>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index 94166ef5db5e..428499532005 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"I-maximize ang Screen"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"I-snap ang Screen"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Hindi mailipat dito ang app"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersive"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"I-restore"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"I-maximize"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"I-restore"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"I-snap pakaliwa"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index ad50a045c924..2fb3f5ab5ea4 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -133,10 +133,8 @@
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"最大化屏幕"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"屏幕快照"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"无法将应用移至此处"</string>
- <!-- no translation found for desktop_mode_maximize_menu_immersive_button_text (559492223133829481) -->
- <skip />
- <!-- no translation found for desktop_mode_maximize_menu_immersive_restore_button_text (4900114367354709257) -->
- <skip />
+ <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"沉浸式"</string>
+ <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"恢复"</string>
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"最大化"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"恢复"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"贴靠左侧"</string>
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/pip/PipContentOverlay.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/pip/PipContentOverlay.java
index eb7ef1478a90..62ca5c687a2a 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/pip/PipContentOverlay.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/pip/PipContentOverlay.java
@@ -18,6 +18,7 @@ package com.android.wm.shell.shared.pip;
import static android.util.TypedValue.COMPLEX_UNIT_DIP;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.TypedArray;
@@ -170,26 +171,34 @@ public abstract class PipContentOverlay {
private final Context mContext;
private final int mAppIconSizePx;
- private final Rect mAppBounds;
+ /**
+ * The bounds of the application window relative to the task leash.
+ */
+ private final Rect mRelativeAppBounds;
private final int mOverlayHalfSize;
private final Matrix mTmpTransform = new Matrix();
private final float[] mTmpFloat9 = new float[9];
private Bitmap mBitmap;
- public PipAppIconOverlay(Context context, Rect appBounds, Rect destinationBounds,
- Drawable appIcon, int appIconSizePx) {
+ // TODO(b/356277166): add non-match_parent support on PIP2.
+ /**
+ * @param context the {@link Context} that contains the icon information
+ * @param relativeAppBounds the bounds of the app window frame relative to the task leash
+ * @param destinationBounds the bounds for rhe PIP task
+ * @param appIcon the app icon {@link Drawable}
+ * @param appIconSizePx the icon dimension in pixel
+ */
+ public PipAppIconOverlay(@NonNull Context context, @NonNull Rect relativeAppBounds,
+ @NonNull Rect destinationBounds, @NonNull Drawable appIcon, int appIconSizePx) {
mContext = context;
final int maxAppIconSizePx = (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP,
MAX_APP_ICON_SIZE_DP, context.getResources().getDisplayMetrics());
mAppIconSizePx = Math.min(maxAppIconSizePx, appIconSizePx);
- final int overlaySize = getOverlaySize(appBounds, destinationBounds);
+ final int overlaySize = getOverlaySize(relativeAppBounds, destinationBounds);
mOverlayHalfSize = overlaySize >> 1;
-
- // When the activity is in the secondary split, make sure the scaling center is not
- // offset.
- mAppBounds = new Rect(0, 0, appBounds.width(), appBounds.height());
+ mRelativeAppBounds = relativeAppBounds;
mBitmap = Bitmap.createBitmap(overlaySize, overlaySize, Bitmap.Config.ARGB_8888);
prepareAppIconOverlay(appIcon);
@@ -206,9 +215,9 @@ public abstract class PipContentOverlay {
* the overlay will be drawn with the max size of the start and end bounds in different
* rotation.
*/
- public static int getOverlaySize(Rect appBounds, Rect destinationBounds) {
- final int appWidth = appBounds.width();
- final int appHeight = appBounds.height();
+ public static int getOverlaySize(Rect overlayBounds, Rect destinationBounds) {
+ final int appWidth = overlayBounds.width();
+ final int appHeight = overlayBounds.height();
return Math.max(Math.max(appWidth, appHeight),
Math.max(destinationBounds.width(), destinationBounds.height())) + 1;
@@ -230,15 +239,15 @@ public abstract class PipContentOverlay {
mTmpTransform.reset();
// In order for the overlay to always cover the pip window, the overlay may have a
// size larger than the pip window. Make sure that app icon is at the center.
- final int appBoundsCenterX = mAppBounds.centerX();
- final int appBoundsCenterY = mAppBounds.centerY();
+ final int appBoundsCenterX = mRelativeAppBounds.centerX();
+ final int appBoundsCenterY = mRelativeAppBounds.centerY();
mTmpTransform.setTranslate(
appBoundsCenterX - mOverlayHalfSize,
appBoundsCenterY - mOverlayHalfSize);
// Scale back the bitmap with the pivot point at center.
final float scale = Math.min(
- (float) mAppBounds.width() / currentBounds.width(),
- (float) mAppBounds.height() / currentBounds.height());
+ (float) mRelativeAppBounds.width() / currentBounds.width(),
+ (float) mRelativeAppBounds.height() / currentBounds.height());
mTmpTransform.postScale(scale, scale, appBoundsCenterX, appBoundsCenterY);
atomicTx.setMatrix(mLeash, mTmpTransform, mTmpFloat9)
.setAlpha(mLeash, fraction < 0.5f ? 0 : (fraction - 0.5f) * 2);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index ae0485f0ad07..f296c710f9a0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -1300,7 +1300,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
final TransitionInfo init = mOpenTransitionInfo;
// Find prepare open target
boolean openShowWallpaper = false;
- final ArrayList<OpenChangeInfo> targets = new ArrayList<>();
+ final ArrayList<SurfaceControl> openSurfaces = new ArrayList<>();
int tmpSize;
for (int j = init.getChanges().size() - 1; j >= 0; --j) {
final TransitionInfo.Change change = init.getChanges().get(j);
@@ -1313,13 +1313,13 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
&& openToken == null) {
continue;
}
- targets.add(new OpenChangeInfo(openComponent, openTaskId, openToken));
+ openSurfaces.add(change.getLeash());
if (change.hasFlags(FLAG_SHOW_WALLPAPER)) {
openShowWallpaper = true;
}
}
}
- if (targets.isEmpty()) {
+ if (openSurfaces.isEmpty()) {
// This shouldn't happen, but if that happen, consume the initial transition anyway.
Log.e(TAG, "Unable to merge following transition, cannot find the gesture "
+ "animated target from the open transition=" + mOpenTransitionInfo);
@@ -1331,7 +1331,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
tmpSize = info.getChanges().size();
for (int j = 0; j < tmpSize; ++j) {
final TransitionInfo.Change change = info.getChanges().get(j);
- if (isOpenChangeMatched(targets, change)) {
+ if (isOpenSurfaceMatched(openSurfaces, change)) {
// This is original close target, potential be close, but cannot determine
// from it.
if (change.hasFlags(FLAG_BACK_GESTURE_ANIMATED)) {
@@ -1352,7 +1352,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
boolean mergePredictive = false;
for (int j = info.getChanges().size() - 1; j >= 0; --j) {
final TransitionInfo.Change change = info.getChanges().get(j);
- if (isOpenChangeMatched(targets, change)) {
+ if (isOpenSurfaceMatched(openSurfaces, change)) {
if (TransitionUtil.isClosingMode(change.getMode())) {
excludeOpenTarget = true;
}
@@ -1373,7 +1373,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
if (change.hasFlags(FLAG_IS_WALLPAPER)) {
continue;
}
- if (isOpenChangeMatched(targets, change)) {
+ if (isOpenSurfaceMatched(openSurfaces, change)) {
if (excludeOpenTarget) {
// App has triggered another change during predictive back
// transition, filter out predictive back target.
@@ -1408,7 +1408,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
if (nonBackClose && nonBackOpen) {
for (int j = info.getChanges().size() - 1; j >= 0; --j) {
final TransitionInfo.Change change = info.getChanges().get(j);
- if (isOpenChangeMatched(targets, change)) {
+ if (isOpenSurfaceMatched(openSurfaces, change)) {
info.getChanges().remove(j);
} else if ((openShowWallpaper && change.hasFlags(FLAG_IS_WALLPAPER))) {
info.getChanges().remove(j);
@@ -1692,22 +1692,10 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
return INVALID_TASK_ID;
}
- private static boolean isSameChangeTarget(ComponentName topActivity, int taskId,
- WindowContainerToken token, TransitionInfo.Change change) {
- final ComponentName openChange = findComponentName(change);
- final int firstTaskId = findTaskId(change);
- final WindowContainerToken openToken = findToken(change);
- return (openChange != null && openChange.equals(topActivity))
- || (firstTaskId != INVALID_TASK_ID && firstTaskId == taskId)
- || (openToken != null && openToken.equals(token));
- }
-
- static boolean isOpenChangeMatched(@NonNull ArrayList<OpenChangeInfo> targets,
+ static boolean isOpenSurfaceMatched(@NonNull ArrayList<SurfaceControl> openSurfaces,
TransitionInfo.Change change) {
- for (int i = targets.size() - 1; i >= 0; --i) {
- final OpenChangeInfo next = targets.get(i);
- if (isSameChangeTarget(next.mOpenComponent, next.mOpenTaskId, next.mOpenToken,
- change)) {
+ for (int i = openSurfaces.size() - 1; i >= 0; --i) {
+ if (openSurfaces.get(i).isSameSurface(change.getLeash())) {
return true;
}
}
@@ -1771,16 +1759,4 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
}
}
}
-
- static class OpenChangeInfo {
- final ComponentName mOpenComponent;
- final int mOpenTaskId;
- final WindowContainerToken mOpenToken;
- OpenChangeInfo(ComponentName openComponent, int openTaskId,
- WindowContainerToken openToken) {
- mOpenComponent = openComponent;
- mOpenTaskId = openTaskId;
- mOpenToken = openToken;
- }
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index d1246d35e35e..5f0eed9daa1a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -1212,7 +1212,7 @@ public class BubbleController implements ConfigurationChangeListener,
*/
public void startBubbleDrag(String bubbleKey) {
if (mBubbleData.getSelectedBubble() != null) {
- mBubbleBarViewCallback.expansionChanged(/* isExpanded = */ false);
+ collapseExpandedViewForBubbleBar();
}
if (mBubbleStateListener != null) {
boolean overflow = BubbleOverflow.KEY.equals(bubbleKey);
@@ -1304,6 +1304,7 @@ public class BubbleController implements ConfigurationChangeListener,
if (BubbleOverflow.KEY.equals(key)) {
mBubbleData.setSelectedBubbleFromLauncher(mBubbleData.getOverflow());
mLayerView.showExpandedView(mBubbleData.getOverflow());
+ mLogger.log(BubbleLogger.Event.BUBBLE_BAR_EXPANDED);
return;
}
@@ -1315,6 +1316,7 @@ public class BubbleController implements ConfigurationChangeListener,
// already in the stack
mBubbleData.setSelectedBubbleFromLauncher(b);
mLayerView.showExpandedView(b);
+ mLogger.log(b, BubbleLogger.Event.BUBBLE_BAR_EXPANDED);
} else if (mBubbleData.hasOverflowBubbleWithKey(b.getKey())) {
// TODO: (b/271468319) handle overflow
} else {
@@ -2024,12 +2026,16 @@ public class BubbleController implements ConfigurationChangeListener,
public void expansionChanged(boolean isExpanded) {
// in bubble bar mode, let the request to show the expanded view come from launcher.
// only collapse here if we're collapsing.
- if (mLayerView != null && !isExpanded) {
- if (mBubblePositioner.isImeVisible()) {
- // If we're collapsing, hide the IME
- hideCurrentInputMethod();
- }
- mLayerView.collapse();
+ if (!isExpanded) {
+ collapseExpandedViewForBubbleBar();
+ }
+
+ BubbleLogger.Event event = isExpanded ? BubbleLogger.Event.BUBBLE_BAR_EXPANDED
+ : BubbleLogger.Event.BUBBLE_BAR_COLLAPSED;
+ if (mBubbleData.getSelectedBubble() instanceof Bubble bubble) {
+ mLogger.log(bubble, event);
+ } else {
+ mLogger.log(event);
}
}
@@ -2182,6 +2188,16 @@ public class BubbleController implements ConfigurationChangeListener,
}
}
+ private void collapseExpandedViewForBubbleBar() {
+ if (mLayerView != null && mLayerView.isExpanded()) {
+ if (mBubblePositioner.isImeVisible()) {
+ // If we're collapsing, hide the IME
+ hideCurrentInputMethod();
+ }
+ mLayerView.collapse();
+ }
+ }
+
private void updateOverflowButtonDot() {
BubbleOverflow overflow = mBubbleData.getOverflow();
if (overflow == null) return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
index b29e49a48428..813772f20a8a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
@@ -71,6 +71,11 @@ public class DividerSnapAlgorithm {
*/
private static final int SNAP_MODE_MINIMIZED = 3;
+ /**
+ * A mode where apps can be "flexibly offscreen" on smaller displays.
+ */
+ private static final int SNAP_FLEXIBLE_SPLIT = 4;
+
private final float mMinFlingVelocityPxPerSecond;
private final float mMinDismissVelocityPxPerSecond;
private final int mDisplayWidth;
@@ -78,6 +83,7 @@ public class DividerSnapAlgorithm {
private final int mDividerSize;
private final ArrayList<SnapTarget> mTargets = new ArrayList<>();
private final Rect mInsets = new Rect();
+ private final Rect mPinnedTaskbarInsets = new Rect();
private final int mSnapMode;
private final boolean mFreeSnapMode;
private final int mMinimalSizeResizableTask;
@@ -88,6 +94,8 @@ public class DividerSnapAlgorithm {
/** Allows split ratios that go offscreen (a.k.a. "flexible split") */
private final boolean mAllowOffscreenRatios;
private final boolean mIsLeftRightSplit;
+ /** In SNAP_MODE_MINIMIZED, the side of the screen on which an app will "dock" when minimized */
+ private final int mDockSide;
/** The first target which is still splitting the screen */
private final SnapTarget mFirstSplitTarget;
@@ -101,14 +109,14 @@ public class DividerSnapAlgorithm {
public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
- boolean isLeftRightSplit, Rect insets, int dockSide) {
+ boolean isLeftRightSplit, Rect insets, Rect pinnedTaskbarInsets, int dockSide) {
this(res, displayWidth, displayHeight, dividerSize, isLeftRightSplit, insets,
- dockSide, false /* minimized */, true /* resizable */);
+ pinnedTaskbarInsets, dockSide, false /* minimized */, true /* resizable */);
}
public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
- boolean isLeftRightSplit, Rect insets, int dockSide, boolean isMinimizedMode,
- boolean isHomeResizable) {
+ boolean isLeftRightSplit, Rect insets, Rect pinnedTaskbarInsets, int dockSide,
+ boolean isMinimizedMode, boolean isHomeResizable) {
mMinFlingVelocityPxPerSecond =
MIN_FLING_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density;
mMinDismissVelocityPxPerSecond =
@@ -117,10 +125,11 @@ public class DividerSnapAlgorithm {
mDisplayWidth = displayWidth;
mDisplayHeight = displayHeight;
mIsLeftRightSplit = isLeftRightSplit;
+ mDockSide = dockSide;
mInsets.set(insets);
+ mPinnedTaskbarInsets.set(pinnedTaskbarInsets);
if (Flags.enableFlexibleTwoAppSplit()) {
- // In flexible split, we always use a fixed ratio (50%, 66%, or 90%) for splitting
- mSnapMode = SNAP_FIXED_RATIO;
+ mSnapMode = SNAP_FLEXIBLE_SPLIT;
} else {
// Set SNAP_MODE_MINIMIZED, SNAP_MODE_16_9, or SNAP_FIXED_RATIO depending on config
mSnapMode = isMinimizedMode
@@ -140,7 +149,7 @@ public class DividerSnapAlgorithm {
mAllowOffscreenRatios = SplitScreenUtils.allowOffscreenRatios(res);
mTaskHeightInMinimizedMode = isHomeResizable ? res.getDimensionPixelSize(
com.android.internal.R.dimen.task_height_of_minimized_mode) : 0;
- calculateTargets(isLeftRightSplit, dockSide);
+ calculateTargets();
mFirstSplitTarget = mTargets.get(1);
mLastSplitTarget = mTargets.get(mTargets.size() - 2);
mDismissStartTarget = mTargets.get(0);
@@ -276,28 +285,31 @@ public class DividerSnapAlgorithm {
return mTargets.get(minIndex);
}
- private void calculateTargets(boolean isLeftRightSplit, int dockedSide) {
+ private void calculateTargets() {
mTargets.clear();
- int dividerMax = isLeftRightSplit
+ int dividerMax = mIsLeftRightSplit
? mDisplayWidth
: mDisplayHeight;
int startPos = -mDividerSize;
- if (dockedSide == DOCKED_RIGHT) {
+ if (mDockSide == DOCKED_RIGHT) {
startPos += mInsets.left;
}
mTargets.add(new SnapTarget(startPos, SNAP_TO_START_AND_DISMISS, 0.35f));
switch (mSnapMode) {
case SNAP_MODE_16_9:
- addRatio16_9Targets(isLeftRightSplit, dividerMax);
+ addRatio16_9Targets(mIsLeftRightSplit, dividerMax);
break;
case SNAP_FIXED_RATIO:
- addFixedDivisionTargets(isLeftRightSplit, dividerMax);
+ addFixedDivisionTargets(mIsLeftRightSplit, dividerMax);
break;
case SNAP_ONLY_1_1:
- addMiddleTarget(isLeftRightSplit);
+ addMiddleTarget(mIsLeftRightSplit);
break;
case SNAP_MODE_MINIMIZED:
- addMinimizedTarget(isLeftRightSplit, dockedSide);
+ addMinimizedTarget(mIsLeftRightSplit, mDockSide);
+ break;
+ case SNAP_FLEXIBLE_SPLIT:
+ addFlexSplitTargets(mIsLeftRightSplit, dividerMax);
break;
}
mTargets.add(new SnapTarget(dividerMax, SNAP_TO_END_AND_DISMISS, 0.35f));
@@ -321,18 +333,9 @@ public class DividerSnapAlgorithm {
? mDisplayWidth - mInsets.right
: mDisplayHeight - mInsets.bottom;
- int size;
- if (Flags.enableFlexibleTwoAppSplit()) {
- float ratio = areOffscreenRatiosSupported()
- ? SplitLayout.OFFSCREEN_ASYMMETRIC_RATIO
- : SplitLayout.ONSCREEN_ONLY_ASYMMETRIC_RATIO;
- size = (int) (ratio * (end - start)) - mDividerSize / 2;
- } else {
- size = (int) (mFixedRatio * (end - start)) - mDividerSize / 2;
-
- if (mCalculateRatiosBasedOnAvailableSpace) {
- size = Math.max(size, mMinimalSizeResizableTask);
- }
+ int size = (int) (mFixedRatio * (end - start)) - mDividerSize / 2;
+ if (mCalculateRatiosBasedOnAvailableSpace) {
+ size = Math.max(size, mMinimalSizeResizableTask);
}
int topPosition = start + size;
@@ -340,6 +343,24 @@ public class DividerSnapAlgorithm {
addNonDismissingTargets(isLeftRightSplit, topPosition, bottomPosition, dividerMax);
}
+ private void addFlexSplitTargets(boolean isLeftRightSplit, int dividerMax) {
+ int start = 0;
+ int end = isLeftRightSplit ? mDisplayWidth : mDisplayHeight;
+ int pinnedTaskbarShiftStart = isLeftRightSplit
+ ? mPinnedTaskbarInsets.left : mPinnedTaskbarInsets.top;
+ int pinnedTaskbarShiftEnd = isLeftRightSplit
+ ? mPinnedTaskbarInsets.right : mPinnedTaskbarInsets.bottom;
+
+ float ratio = areOffscreenRatiosSupported()
+ ? SplitLayout.OFFSCREEN_ASYMMETRIC_RATIO
+ : SplitLayout.ONSCREEN_ONLY_ASYMMETRIC_RATIO;
+ int size = (int) (ratio * (end - start)) - mDividerSize / 2;
+
+ int leftTopPosition = start + pinnedTaskbarShiftStart + size;
+ int rightBottomPosition = end - pinnedTaskbarShiftEnd - size - mDividerSize;
+ addNonDismissingTargets(isLeftRightSplit, leftTopPosition, rightBottomPosition, dividerMax);
+ }
+
private void addRatio16_9Targets(boolean isLeftRightSplit, int dividerMax) {
int start = isLeftRightSplit ? mInsets.left : mInsets.top;
int end = isLeftRightSplit
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index b1e0e9eab5d0..dab30b0f0b96 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -49,10 +49,13 @@ import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Handler;
import android.view.Display;
+import android.view.InsetsController;
+import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.RoundedCorner;
@@ -153,6 +156,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
private final ResizingEffectPolicy mSurfaceEffectPolicy;
private final ShellTaskOrganizer mTaskOrganizer;
private final InsetsState mInsetsState = new InsetsState();
+ private Insets mPinnedTaskbarInsets = Insets.NONE;
private Context mContext;
@VisibleForTesting DividerSnapAlgorithm mDividerSnapAlgorithm;
@@ -523,6 +527,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
@Override
public void insetsChanged(InsetsState insetsState) {
mInsetsState.set(insetsState);
+
if (!mInitialized) {
return;
}
@@ -531,9 +536,51 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
// flicker.
return;
}
+
+ // Check to see if insets changed in such a way that the divider algorithm needs to be
+ // recalculated.
+ Insets pinnedTaskbarInsets = calculatePinnedTaskbarInsets(insetsState);
+ if (!mPinnedTaskbarInsets.equals(pinnedTaskbarInsets)) {
+ mPinnedTaskbarInsets = pinnedTaskbarInsets;
+ // Refresh the DividerSnapAlgorithm.
+ mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds);
+ // If the divider is no longer placed on a snap point, animate it to the nearest one.
+ DividerSnapAlgorithm.SnapTarget snapTarget =
+ findSnapTarget(mDividerPosition, 0, false /* hardDismiss */);
+ if (snapTarget.position != mDividerPosition) {
+ snapToTarget(mDividerPosition, snapTarget,
+ InsetsController.ANIMATION_DURATION_RESIZE,
+ InsetsController.RESIZE_INTERPOLATOR);
+ }
+ }
+
mSplitWindowManager.onInsetsChanged(insetsState);
}
+ /**
+ * Calculates the insets that might trigger a divider algorithm recalculation. Currently, only
+ * pinned Taskbar does this, and only when the IME is not showing.
+ */
+ private Insets calculatePinnedTaskbarInsets(InsetsState insetsState) {
+ if (insetsState.isSourceOrDefaultVisible(InsetsSource.ID_IME, WindowInsets.Type.ime())) {
+ return Insets.NONE;
+ }
+
+ // If IME is not showing...
+ for (int i = insetsState.sourceSize() - 1; i >= 0; i--) {
+ final InsetsSource source = insetsState.sourceAt(i);
+ // and Taskbar is pinned...
+ if (source.getType() == WindowInsets.Type.navigationBars()
+ && source.hasFlags(InsetsSource.FLAG_INSETS_ROUNDED_CORNER)) {
+ // Return Insets representing the pinned taskbar state.
+ return source.calculateVisibleInsets(mRootBounds);
+ }
+ }
+
+ // Else, divider can calculate based on the full display.
+ return Insets.NONE;
+ }
+
@Override
public void insetsControlChanged(InsetsState insetsState,
InsetsSourceControl[] activeControls) {
@@ -631,8 +678,8 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
}
/**
- * Same as {@link #snapToTarget(int, SnapTarget)}, with default animation duration and
- * interpolator.
+ * Same as {@link #snapToTarget(int, SnapTarget, int, Interpolator)}, with default animation
+ * duration and interpolator.
*/
public void snapToTarget(int currentPosition, SnapTarget snapTarget) {
snapToTarget(currentPosition, snapTarget, FLING_RESIZE_DURATION,
@@ -683,6 +730,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
mDividerSize,
mIsLeftRightSplit,
insets,
+ mPinnedTaskbarInsets.toRect(),
mIsLeftRightSplit ? DOCKED_LEFT : DOCKED_TOP /* dockSide */);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 615dad31534f..817be3b1fe0d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -970,7 +970,10 @@ public abstract class WMShellModule {
CloseDesktopTaskTransitionHandler closeDesktopTaskTransitionHandler,
Optional<DesktopImmersiveController> desktopImmersiveController,
InteractionJankMonitor interactionJankMonitor,
- @ShellMainThread Handler handler) {
+ @ShellMainThread Handler handler,
+ ShellInit shellInit,
+ RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer
+ ) {
if (!DesktopModeStatus.canEnterDesktopMode(context)) {
return Optional.empty();
}
@@ -983,7 +986,9 @@ public abstract class WMShellModule {
closeDesktopTaskTransitionHandler,
desktopImmersiveController.get(),
interactionJankMonitor,
- handler));
+ handler,
+ shellInit,
+ rootTaskDisplayAreaOrganizer));
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt
index 0bc571f4782c..48bb2a8b4a74 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt
@@ -25,6 +25,7 @@ import android.view.SurfaceControl
import android.view.WindowManager
import android.window.DesktopModeFlags
import android.window.TransitionInfo
+import android.window.TransitionInfo.Change
import android.window.TransitionRequestInfo
import android.window.WindowContainerTransaction
import androidx.annotation.VisibleForTesting
@@ -32,10 +33,13 @@ import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_C
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.protolog.ProtoLog
import com.android.window.flags.Flags
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.freeform.FreeformTaskTransitionHandler
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
+import com.android.wm.shell.shared.TransitionUtil
import com.android.wm.shell.shared.annotations.ShellMainThread
+import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.MixedTransitionHandler
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.transition.Transitions.TransitionFinishCallback
@@ -50,8 +54,14 @@ class DesktopMixedTransitionHandler(
private val desktopImmersiveController: DesktopImmersiveController,
private val interactionJankMonitor: InteractionJankMonitor,
@ShellMainThread private val handler: Handler,
+ shellInit: ShellInit,
+ private val rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
) : MixedTransitionHandler, FreeformTaskTransitionStarter {
+ init {
+ shellInit.addInitCallback ({ transitions.addHandler(this) }, this)
+ }
+
@VisibleForTesting
val pendingMixedTransitions = mutableListOf<PendingMixedTransition>()
@@ -85,9 +95,11 @@ class DesktopMixedTransitionHandler(
@WindowManager.TransitionType transitionType: Int,
wct: WindowContainerTransaction,
taskId: Int,
+ minimizingTaskId: Int? = null,
exitingImmersiveTask: Int? = null,
): IBinder {
- if (!Flags.enableFullyImmersiveInDesktop()) {
+ if (!Flags.enableFullyImmersiveInDesktop() &&
+ !DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS.isTrue) {
return transitions.startTransition(transitionType, wct, /* handler= */ null)
}
if (exitingImmersiveTask == null) {
@@ -103,11 +115,17 @@ class DesktopMixedTransitionHandler(
pendingMixedTransitions.add(PendingMixedTransition.Launch(
transition = transition,
launchingTask = taskId,
- exitingImmersiveTask = exitingImmersiveTask
+ minimizingTask = minimizingTaskId,
+ exitingImmersiveTask = exitingImmersiveTask,
))
}
}
+ /** Notifies this handler that there is a pending transition for it to handle. */
+ fun addPendingMixedTransition(pendingMixedTransition: PendingMixedTransition) {
+ pendingMixedTransitions.add(pendingMixedTransition)
+ }
+
/** Returns null, as it only handles transitions started from Shell. */
override fun handleRequest(
transition: IBinder,
@@ -123,7 +141,7 @@ class DesktopMixedTransitionHandler(
): Boolean {
val pending = pendingMixedTransitions.find { pending -> pending.transition == transition }
?: return false.also {
- logW("Should have pending desktop transition")
+ logV("No pending desktop transition")
}
pendingMixedTransitions.remove(pending)
logV("Animating pending mixed transition: %s", pending)
@@ -191,6 +209,9 @@ class DesktopMixedTransitionHandler(
val immersiveExitChange = pending.exitingImmersiveTask?.let { exitingTask ->
findDesktopTaskChange(info, exitingTask)
}
+ val minimizeChange = pending.minimizingTask?.let { minimizingTask ->
+ findDesktopTaskChange(info, minimizingTask)
+ }
val launchChange = findDesktopTaskChange(info, pending.launchingTask)
?: error("Should have pending launching task change")
@@ -204,9 +225,17 @@ class DesktopMixedTransitionHandler(
}
logV(
- "Animating pending mixed launch transition task#%d immersiveExitTask#%s",
- launchChange.taskInfo!!.taskId, immersiveExitChange?.taskInfo?.taskId
+ "Animating mixed launch transition task#%d, minimizingTask#%s immersiveExitTask#%s",
+ launchChange.taskInfo!!.taskId, minimizeChange?.taskInfo?.taskId,
+ immersiveExitChange?.taskInfo?.taskId
)
+ if (DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS.isTrue) {
+ // Only apply minimize change reparenting here if we implement the new app launch
+ // transitions, otherwise this reparenting is handled in the default handler.
+ minimizeChange?.let {
+ applyMinimizeChangeReparenting(info, minimizeChange, startTransaction)
+ }
+ }
if (immersiveExitChange != null) {
subAnimationCount = 2
// Animate the immersive exit change separately.
@@ -257,7 +286,7 @@ class DesktopMixedTransitionHandler(
change: TransitionInfo.Change,
startTransaction: SurfaceControl.Transaction,
finishTransaction: SurfaceControl.Transaction,
- finishCallback: Transitions.TransitionFinishCallback,
+ finishCallback: TransitionFinishCallback,
): Boolean {
// Starting the jank trace if closing the last window in desktop mode.
interactionJankMonitor.begin(
@@ -280,6 +309,28 @@ class DesktopMixedTransitionHandler(
)
}
+ /**
+ * Reparent the minimizing task back to its root display area.
+ *
+ * During the launch/minimize animation the all animated tasks will be reparented to a
+ * transition leash shown in front of other desktop tasks. Reparenting the minimizing task back
+ * to its root display area ensures that task stays behind other desktop tasks during the
+ * animation.
+ */
+ private fun applyMinimizeChangeReparenting(
+ info: TransitionInfo,
+ minimizeChange: Change,
+ startTransaction: SurfaceControl.Transaction,
+ ) {
+ require(TransitionUtil.isOpeningMode(info.type))
+ require(minimizeChange.taskInfo != null)
+ val taskInfo = minimizeChange.taskInfo!!
+ require(taskInfo.isFreeform)
+ logV("Reparenting minimizing task#%d", taskInfo.taskId)
+ rootTaskDisplayAreaOrganizer.reparentToDisplayArea(
+ taskInfo.displayId, minimizeChange.leash, startTransaction)
+ }
+
private fun dispatchToLeftoverHandler(
transition: IBinder,
info: TransitionInfo,
@@ -341,6 +392,7 @@ class DesktopMixedTransitionHandler(
data class Launch(
override val transition: IBinder,
val launchingTask: Int,
+ val minimizingTask: Int?,
val exitingImmersiveTask: Int?,
) : PendingMixedTransition()
}
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 515b203dd492..75f8839692a2 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
@@ -698,6 +698,7 @@ class DesktopTasksController(
transitionType = transitionType,
wct = wct,
taskId = taskId,
+ minimizingTaskId = taskIdToMinimize,
exitingImmersiveTask = exitingImmersiveTask,
)
taskIdToMinimize?.let { addPendingMinimizeTransition(t, it) }
@@ -1434,6 +1435,7 @@ class DesktopTasksController(
)
val transition = transitions.startTransition(TRANSIT_OPEN, wct, null)
taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
+ addPendingAppLaunchTransition(transition, requestedTaskId, taskIdToMinimize)
exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
} else {
val splitPosition = splitScreenController.determineNewInstancePosition(callingTask)
@@ -1574,6 +1576,7 @@ class DesktopTasksController(
desktopImmersiveController.exitImmersiveIfApplicable(transition, wct, task.displayId)
// 2) minimize a Task if needed.
val taskIdToMinimize = addAndGetMinimizeChanges(task.displayId, wct, task.taskId)
+ addPendingAppLaunchTransition(transition, task.taskId, taskIdToMinimize)
if (taskIdToMinimize != null) {
addPendingMinimizeTransition(transition, taskIdToMinimize)
return wct
@@ -1605,6 +1608,7 @@ class DesktopTasksController(
// minimize another Task.
val taskIdToMinimize = addAndGetMinimizeChanges(task.displayId, wct, task.taskId)
taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
+ addPendingAppLaunchTransition(transition, task.taskId, taskIdToMinimize)
desktopImmersiveController.exitImmersiveIfApplicable(
transition, wct, task.displayId
)
@@ -1785,6 +1789,20 @@ class DesktopTasksController(
}
}
+ private fun addPendingAppLaunchTransition(
+ transition: IBinder,
+ launchTaskId: Int,
+ minimizeTaskId: Int?,
+ ) {
+ if (!DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS.isTrue) {
+ return
+ }
+ // TODO b/359523924: pass immersive task here?
+ desktopMixedTransitionHandler.addPendingMixedTransition(
+ DesktopMixedTransitionHandler.PendingMixedTransition.Launch(
+ transition, launchTaskId, minimizeTaskId, /* exitingImmersiveTask= */ null))
+ }
+
fun removeDesktop(displayId: Int) {
if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue()) return
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index f060158766fe..4aeecbec7dfb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -30,6 +30,7 @@ import android.annotation.NonNull;
import android.app.TaskInfo;
import android.content.Context;
import android.content.pm.ActivityInfo;
+import android.graphics.Point;
import android.graphics.Rect;
import android.os.SystemClock;
import android.view.Surface;
@@ -152,7 +153,6 @@ public class PipAnimationController {
return mCurrentAnimator;
}
- @SuppressWarnings("unchecked")
/**
* Construct and return an animator that animates from the {@param startBounds} to the
* {@param endBounds} with the given {@param direction}. If {@param direction} is type
@@ -171,6 +171,7 @@ public class PipAnimationController {
* leaving PiP to fullscreen, and the {@param endBounds} is the fullscreen bounds before the
* rotation change.
*/
+ @SuppressWarnings("unchecked")
@VisibleForTesting
public PipTransitionAnimator getAnimator(TaskInfo taskInfo, SurfaceControl leash,
Rect baseBounds, Rect startBounds, Rect endBounds, Rect sourceHintRect,
@@ -566,7 +567,7 @@ public class PipAnimationController {
}
getSurfaceTransactionHelper()
.resetScale(tx, leash, getDestinationBounds())
- .crop(tx, leash, getDestinationBounds())
+ .cropAndPosition(tx, leash, getDestinationBounds())
.round(tx, leash, true /* applyCornerRadius */)
.shadow(tx, leash, shouldApplyShadowRadius());
tx.show(leash);
@@ -590,18 +591,50 @@ public class PipAnimationController {
// Just for simplicity we'll interpolate between the source rect hint insets and empty
// insets to calculate the window crop
final Rect initialSourceValue;
+ final Rect mainWindowFrame = taskInfo.topActivityMainWindowFrame;
+ final boolean hasNonMatchFrame = mainWindowFrame != null;
+ final boolean changeOrientation =
+ rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270;
+ final Rect baseBounds = new Rect(baseValue);
+ final Rect startBounds = new Rect(startValue);
+ final Rect endBounds = new Rect(endValue);
if (isOutPipDirection) {
- initialSourceValue = new Rect(endValue);
+ // TODO(b/356277166): handle rotation change with activity that provides main window
+ // frame.
+ if (hasNonMatchFrame && !changeOrientation) {
+ endBounds.set(mainWindowFrame);
+ }
+ initialSourceValue = new Rect(endBounds);
+ } else if (isInPipDirection) {
+ if (hasNonMatchFrame) {
+ baseBounds.set(mainWindowFrame);
+ if (startValue.equals(baseValue)) {
+ // If the start value is at initial state as in PIP animation, also override
+ // the start bounds with nonMatchParentBounds.
+ startBounds.set(mainWindowFrame);
+ }
+ }
+ initialSourceValue = new Rect(baseBounds);
} else {
- initialSourceValue = new Rect(baseValue);
+ // Note that we assume the window bounds always match task bounds in PIP mode.
+ initialSourceValue = new Rect(baseBounds);
+ }
+
+ final Point leashOffset;
+ if (isInPipDirection) {
+ leashOffset = new Point(baseValue.left, baseValue.top);
+ } else if (isOutPipDirection) {
+ leashOffset = new Point(endValue.left, endValue.top);
+ } else {
+ leashOffset = new Point(baseValue.left, baseValue.top);
}
final Rect rotatedEndRect;
final Rect lastEndRect;
final Rect initialContainerRect;
- if (rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270) {
- lastEndRect = new Rect(endValue);
- rotatedEndRect = new Rect(endValue);
+ if (changeOrientation) {
+ lastEndRect = new Rect(endBounds);
+ rotatedEndRect = new Rect(endBounds);
// Rotate the end bounds according to the rotation delta because the display will
// be rotated to the same orientation.
rotateBounds(rotatedEndRect, initialSourceValue, rotationDelta);
@@ -617,9 +650,9 @@ public class PipAnimationController {
// Crop a Rect matches the aspect ratio and pivots at the center point.
// This is done for entering case only.
if (isInPipDirection(direction)) {
- final float aspectRatio = endValue.width() / (float) endValue.height();
+ final float aspectRatio = endBounds.width() / (float) endBounds.height();
adjustedSourceRectHint.set(PipUtils.getEnterPipWithOverlaySrcRectHint(
- startValue, aspectRatio));
+ startBounds, aspectRatio));
}
} else {
adjustedSourceRectHint.set(sourceRectHint);
@@ -644,7 +677,7 @@ public class PipAnimationController {
// construct new Rect instances in case they are recycled
return new PipTransitionAnimator<Rect>(taskInfo, leash, ANIM_TYPE_BOUNDS,
- endValue, new Rect(baseValue), new Rect(startValue), new Rect(endValue)) {
+ endBounds, new Rect(baseBounds), new Rect(startBounds), new Rect(endBounds)) {
private final RectEvaluator mRectEvaluator = new RectEvaluator(new Rect());
private final RectEvaluator mInsetsEvaluator = new RectEvaluator(new Rect());
@@ -668,11 +701,22 @@ public class PipAnimationController {
setCurrentValue(bounds);
if (inScaleTransition() || adjustedSourceRectHint.isEmpty()) {
if (isOutPipDirection) {
- getSurfaceTransactionHelper().crop(tx, leash, end)
- .scale(tx, leash, end, bounds);
+ // Use the bounds relative to the task leash in case the leash does not
+ // start from (0, 0).
+ final Rect relativeEndBounds = new Rect(end);
+ relativeEndBounds.offset(-leashOffset.x, -leashOffset.y);
+ getSurfaceTransactionHelper()
+ .crop(tx, leash, relativeEndBounds)
+ .scale(tx, leash, relativeEndBounds, bounds,
+ false /* shouldOffset */);
} else {
- getSurfaceTransactionHelper().crop(tx, leash, base)
- .scale(tx, leash, base, bounds, angle)
+ // TODO(b/356277166): add support to specify sourceRectHint with
+ // non-match parent activity.
+ // If there's a PIP resize animation, we should offset the bounds to
+ // (0, 0) since the window bounds should match the leash bounds in PIP
+ // mode.
+ getSurfaceTransactionHelper().cropAndPosition(tx, leash, base)
+ .scale(tx, leash, base, bounds, angle, inScaleTransition())
.round(tx, leash, base, bounds)
.shadow(tx, leash, shouldApplyShadowRadius());
}
@@ -680,7 +724,7 @@ public class PipAnimationController {
final Rect insets = computeInsets(fraction);
getSurfaceTransactionHelper().scaleAndCrop(tx, leash,
adjustedSourceRectHint, initialSourceValue, bounds, insets,
- isInPipDirection, fraction);
+ isInPipDirection, fraction, leashOffset);
final Rect sourceBounds = new Rect(initialContainerRect);
sourceBounds.inset(insets);
getSurfaceTransactionHelper()
@@ -733,8 +777,7 @@ public class PipAnimationController {
getSurfaceTransactionHelper()
.rotateAndScaleWithCrop(tx, leash, initialContainerRect, bounds,
insets, degree, x, y, isOutPipDirection,
- rotationDelta == ROTATION_270 /* clockwise */);
- getSurfaceTransactionHelper()
+ rotationDelta == ROTATION_270 /* clockwise */)
.round(tx, leash, sourceBounds, bounds)
.shadow(tx, leash, shouldApplyShadowRadius());
if (!handlePipTransaction(leash, tx, bounds, 1f /* alpha */)) {
@@ -772,7 +815,7 @@ public class PipAnimationController {
tx.setPosition(leash, 0, 0);
tx.setWindowCrop(leash, 0, 0);
} else {
- getSurfaceTransactionHelper().crop(tx, leash, destBounds);
+ getSurfaceTransactionHelper().cropAndPosition(tx, leash, destBounds);
}
if (mContentOverlay != null) {
clearContentOverlay();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
index 3d1994cac534..b02bd0ffec6c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
@@ -16,8 +16,10 @@
package com.android.wm.shell.pip;
+import android.annotation.NonNull;
import android.content.Context;
import android.graphics.Matrix;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.view.Choreographer;
@@ -68,52 +70,102 @@ public class PipSurfaceTransactionHelper {
* Operates the crop (and position) on a given transaction and leash
* @return same {@link PipSurfaceTransactionHelper} instance for method chaining
*/
- public PipSurfaceTransactionHelper crop(SurfaceControl.Transaction tx, SurfaceControl leash,
- Rect destinationBounds) {
+ public PipSurfaceTransactionHelper cropAndPosition(@NonNull SurfaceControl.Transaction tx,
+ @NonNull SurfaceControl leash, @NonNull Rect destinationBounds) {
tx.setWindowCrop(leash, destinationBounds.width(), destinationBounds.height())
.setPosition(leash, destinationBounds.left, destinationBounds.top);
return this;
}
/**
+ * Operates {@link SurfaceControl.Transaction#setCrop} on a given transaction and leash.
+ *
+ * @param tx the transaction to apply
+ * @param leash the leash to crop
+ * @param relativeDestinationBounds the bounds to crop, which is relative to the leash
+ * coordinate
+ * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+ */
+ public PipSurfaceTransactionHelper crop(@NonNull SurfaceControl.Transaction tx,
+ @NonNull SurfaceControl leash, @NonNull Rect relativeDestinationBounds) {
+ tx.setCrop(leash, relativeDestinationBounds);
+ return this;
+ }
+
+ /**
* Operates the scale (setMatrix) on a given transaction and leash
* @return same {@link PipSurfaceTransactionHelper} instance for method chaining
*/
public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
Rect sourceBounds, Rect destinationBounds) {
mTmpDestinationRectF.set(destinationBounds);
- return scale(tx, leash, sourceBounds, mTmpDestinationRectF, 0 /* degrees */);
+ return scale(tx, leash, sourceBounds, mTmpDestinationRectF, 0 /* degrees */,
+ true /* shouldOffset */);
}
/**
* Operates the scale (setMatrix) on a given transaction and leash
* @return same {@link PipSurfaceTransactionHelper} instance for method chaining
*/
- public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
- Rect sourceBounds, RectF destinationBounds) {
- return scale(tx, leash, sourceBounds, destinationBounds, 0 /* degrees */);
+ public PipSurfaceTransactionHelper scale(@NonNull SurfaceControl.Transaction tx,
+ @NonNull SurfaceControl leash, @NonNull Rect sourceBounds,
+ @NonNull RectF destinationBounds) {
+ return scale(tx, leash, sourceBounds, destinationBounds, 0 /* degrees */,
+ true /* shouldOffset */);
}
/**
- * Operates the scale (setMatrix) on a given transaction and leash
+ * Operates the scale (setMatrix) on a given transaction and leash.
+ *
+ * @param shouldOffset {@code true} to offset the leash to (0, 0)
* @return same {@link PipSurfaceTransactionHelper} instance for method chaining
*/
- public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
- Rect sourceBounds, Rect destinationBounds, float degrees) {
+ public PipSurfaceTransactionHelper scale(@NonNull SurfaceControl.Transaction tx,
+ @NonNull SurfaceControl leash, @NonNull Rect sourceBounds,
+ @NonNull Rect destinationBounds, boolean shouldOffset) {
+ mTmpDestinationRectF.set(destinationBounds);
+ return scale(tx, leash, sourceBounds, mTmpDestinationRectF, 0 /* degrees */, shouldOffset);
+ }
+
+ /**
+ * Operates the scale (setMatrix) on a given transaction and leash.
+ *
+ * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+ */
+ public PipSurfaceTransactionHelper scale(@NonNull SurfaceControl.Transaction tx,
+ @NonNull SurfaceControl leash, @NonNull Rect sourceBounds,
+ @NonNull Rect destinationBounds, float degrees) {
+ return scale(tx, leash, sourceBounds, destinationBounds, degrees, true /* shouldOffset */);
+ }
+
+ /**
+ * Operates the scale (setMatrix) on a given transaction and leash.
+ *
+ * @param shouldOffset {@code true} to offset the leash to (0, 0)
+ * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+ */
+ public PipSurfaceTransactionHelper scale(@NonNull SurfaceControl.Transaction tx,
+ @NonNull SurfaceControl leash, @NonNull Rect sourceBounds,
+ @NonNull Rect destinationBounds, float degrees, boolean shouldOffset) {
mTmpDestinationRectF.set(destinationBounds);
- return scale(tx, leash, sourceBounds, mTmpDestinationRectF, degrees);
+ return scale(tx, leash, sourceBounds, mTmpDestinationRectF, degrees, shouldOffset);
}
/**
* Operates the scale (setMatrix) on a given transaction and leash, along with a rotation.
+ *
+ * @param shouldOffset {@code true} to offset the leash to (0, 0)
* @return same {@link PipSurfaceTransactionHelper} instance for method chaining
*/
- public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
- Rect sourceBounds, RectF destinationBounds, float degrees) {
+ public PipSurfaceTransactionHelper scale(@NonNull SurfaceControl.Transaction tx,
+ @NonNull SurfaceControl leash, @NonNull Rect sourceBounds,
+ @NonNull RectF destinationBounds, float degrees, boolean shouldOffset) {
mTmpSourceRectF.set(sourceBounds);
// We want the matrix to position the surface relative to the screen coordinates so offset
- // the source to 0,0
- mTmpSourceRectF.offsetTo(0, 0);
+ // the source to (0, 0) if {@code shouldOffset} is true.
+ if (shouldOffset) {
+ mTmpSourceRectF.offsetTo(0, 0);
+ }
mTmpDestinationRectF.set(destinationBounds);
mTmpTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL);
mTmpTransform.postRotate(degrees,
@@ -123,17 +175,19 @@ public class PipSurfaceTransactionHelper {
}
/**
- * Operates the scale (setMatrix) on a given transaction and leash
+ * Operates the scale (setMatrix) on a given transaction and leash.
+ *
+ * @param leashOffset the offset of the leash bounds relative to the screen coordinate
* @return same {@link PipSurfaceTransactionHelper} instance for method chaining
*/
- public PipSurfaceTransactionHelper scaleAndCrop(SurfaceControl.Transaction tx,
- SurfaceControl leash, Rect sourceRectHint,
- Rect sourceBounds, Rect destinationBounds, Rect insets,
- boolean isInPipDirection, float fraction) {
+ public PipSurfaceTransactionHelper scaleAndCrop(@NonNull SurfaceControl.Transaction tx,
+ @NonNull SurfaceControl leash, @NonNull Rect sourceRectHint, @NonNull Rect sourceBounds,
+ @NonNull Rect destinationBounds, @NonNull Rect insets, boolean isInPipDirection,
+ float fraction, @NonNull Point leashOffset) {
mTmpDestinationRect.set(sourceBounds);
// Similar to {@link #scale}, we want to position the surface relative to the screen
- // coordinates so offset the bounds to 0,0
- mTmpDestinationRect.offsetTo(0, 0);
+ // coordinates so offset the bounds relative to the leash.
+ mTmpDestinationRect.offset(-leashOffset.x, -leashOffset.y);
mTmpDestinationRect.inset(insets);
// Scale to the bounds no smaller than the destination and offset such that the top/left
// of the scaled inset source rect aligns with the top/left of the destination bounds
@@ -152,13 +206,13 @@ public class PipSurfaceTransactionHelper {
scale = Math.max((float) destinationBounds.width() / sourceBounds.width(),
(float) destinationBounds.height() / sourceBounds.height());
}
- float left = destinationBounds.left - insets.left * scale;
- float top = destinationBounds.top - insets.top * scale;
+ float left = destinationBounds.left - mTmpDestinationRect.left * scale;
+ float top = destinationBounds.top - mTmpDestinationRect.top * scale;
if (scale == 1) {
// Work around the 1 pixel off error by rounding the position down at very beginning.
// We noticed such error from flicker tests, not visually.
- left = sourceBounds.left;
- top = sourceBounds.top;
+ left = leashOffset.x;
+ top = leashOffset.y;
}
mTmpTransform.setScale(scale, scale);
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index b4e03299f14c..c4e63dfdade9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -960,7 +960,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
final SurfaceControl.Transaction boundsChangeTx =
mSurfaceControlTransactionFactory.getTransaction();
mSurfaceTransactionHelper
- .crop(boundsChangeTx, mLeash, destinationBounds)
+ .cropAndPosition(boundsChangeTx, mLeash, destinationBounds)
.round(boundsChangeTx, mLeash, true /* applyCornerRadius */);
mPipTransitionState.setTransitionState(PipTransitionState.ENTRY_SCHEDULED);
@@ -988,7 +988,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
mSurfaceTransactionHelper
.resetScale(tx, mLeash, destinationBounds)
- .crop(tx, mLeash, destinationBounds)
+ .cropAndPosition(tx, mLeash, destinationBounds)
.round(tx, mLeash, isInPip());
// The animation is finished in the Launcher and here we directly apply the final touch.
applyEnterPipSyncTransaction(destinationBounds, () -> {
@@ -1525,7 +1525,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mPipBoundsState.setBounds(toBounds);
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
mSurfaceTransactionHelper
- .crop(tx, mLeash, toBounds)
+ .cropAndPosition(tx, mLeash, toBounds)
.round(tx, mLeash, mPipTransitionState.isInPip());
if (shouldSyncPipTransactionWithMenu()) {
mPipMenuController.resizePipMenu(mLeash, tx, toBounds);
@@ -1628,7 +1628,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
Rect destinationBounds) {
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
mSurfaceTransactionHelper
- .crop(tx, mLeash, destinationBounds)
+ .cropAndPosition(tx, mLeash, destinationBounds)
.resetScale(tx, mLeash, destinationBounds)
.round(tx, mLeash, mPipTransitionState.isInPip());
return tx;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 6da39951efbe..28b91c6cb812 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -30,7 +30,6 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_PIP;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
-import static android.view.WindowManager.transitTypeToString;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
@@ -45,6 +44,7 @@ import static com.android.wm.shell.transition.Transitions.TRANSIT_CLEANUP_PIP_EX
import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP_TO_SPLIT;
import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
+import static com.android.wm.shell.transition.Transitions.transitTypeToString;
import android.annotation.IntDef;
import android.app.ActivityManager;
@@ -551,7 +551,7 @@ public class PipTransition extends PipTransitionController {
}
// Reset the scale with bounds change synchronously.
if (hasValidLeash) {
- mSurfaceTransactionHelper.crop(tx, leash, destinationBounds)
+ mSurfaceTransactionHelper.cropAndPosition(tx, leash, destinationBounds)
.resetScale(tx, leash, destinationBounds)
.round(tx, leash, true /* applyCornerRadius */);
final Rect appBounds = mPipOrganizer.mAppBounds;
@@ -588,7 +588,8 @@ public class PipTransition extends PipTransitionController {
ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: Destination bounds were changed during animation", TAG);
rotateBounds(finishBounds, displayBounds, mEndFixedRotation, displayRotation);
- mSurfaceTransactionHelper.crop(mFinishTransaction, leash, finishBounds);
+ mSurfaceTransactionHelper.cropAndPosition(mFinishTransaction, leash,
+ finishBounds);
}
}
mFinishTransaction = null;
@@ -1068,6 +1069,11 @@ public class PipTransition extends PipTransitionController {
mPipBoundsState.mayUseCachedLauncherShelfHeight();
final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
final Rect currentBounds = pipChange.getStartAbsBounds();
+ // The app bounds should offset relative to the task leash to make the center calculation
+ // correctly.
+ final Rect relativeAppBounds = new Rect(taskInfo.topActivityMainWindowFrame != null
+ ? taskInfo.topActivityMainWindowFrame : currentBounds);
+ relativeAppBounds.offset(-currentBounds.left, -currentBounds.top);
int rotationDelta = deltaRotation(startRotation, endRotation);
Rect sourceHintRect = mPipOrganizer.takeSwipeSourceRectHint();
@@ -1089,6 +1095,8 @@ public class PipTransition extends PipTransitionController {
if (taskInfo.pictureInPictureParams != null
&& taskInfo.pictureInPictureParams.isAutoEnterEnabled()
&& mPipTransitionState.getInSwipePipToHomeTransition()) {
+ // TODO(b/356277166): add support to swipe PIP to home with
+ // non-match parent activity.
handleSwipePipToHomeTransition(startTransaction, finishTransaction, leash,
sourceHintRect, destinationBounds, taskInfo);
return;
@@ -1119,8 +1127,8 @@ public class PipTransition extends PipTransitionController {
// TODO(b/272819817): cleanup the null-check and extra logging.
final boolean hasTopActivityInfo = taskInfo.topActivityInfo != null;
if (hasTopActivityInfo && mFixedRotationState != FIXED_ROTATION_TRANSITION) {
- animator.setAppIconContentOverlay(
- mContext, currentBounds, destinationBounds, taskInfo.topActivityInfo,
+ animator.setAppIconContentOverlay(mContext, relativeAppBounds,
+ destinationBounds, taskInfo.topActivityInfo,
mPipBoundsState.getLauncherState().getAppIconSizePx());
} else {
ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
@@ -1149,14 +1157,14 @@ public class PipTransition extends PipTransitionController {
animationDuration = 0;
}
mSurfaceTransactionHelper
- .crop(finishTransaction, leash, destinationBounds)
+ .cropAndPosition(finishTransaction, leash, destinationBounds)
.round(finishTransaction, leash, true /* applyCornerRadius */);
// Always reset to bounds animation type afterwards.
setEnterAnimationType(ANIM_TYPE_BOUNDS);
} else {
throw new RuntimeException("Unrecognized animation type: " + enterAnimationType);
}
- mPipOrganizer.setContentOverlay(animator.getContentOverlayLeash(), currentBounds);
+ mPipOrganizer.setContentOverlay(animator.getContentOverlayLeash(), relativeAppBounds);
animator.setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
.setPipAnimationCallback(mPipAnimationCallback)
.setDuration(animationDuration);
@@ -1340,11 +1348,11 @@ public class PipTransition extends PipTransitionController {
"%s: Update pip for unhandled transition, change=%s, destBounds=%s, isInPip=%b",
TAG, pipChange, destBounds, isInPip);
mSurfaceTransactionHelper
- .crop(startTransaction, leash, destBounds)
+ .cropAndPosition(startTransaction, leash, destBounds)
.round(startTransaction, leash, isInPip)
.shadow(startTransaction, leash, isInPip);
mSurfaceTransactionHelper
- .crop(finishTransaction, leash, destBounds)
+ .cropAndPosition(finishTransaction, leash, destBounds)
.round(finishTransaction, leash, isInPip)
.shadow(finishTransaction, leash, isInPip);
// Make sure the PiP keeps invisible if it was faded out. If it needs to fade in, that will
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java
index 7a0e6694cb51..d3ae411469cc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java
@@ -23,7 +23,6 @@ import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_PIP;
import static android.view.WindowManager.TRANSIT_TO_BACK;
-import static android.view.WindowManager.transitTypeToString;
import static com.android.wm.shell.common.pip.PipMenuController.ALPHA_NO_CHANGE;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
@@ -35,6 +34,7 @@ import static com.android.wm.shell.pip.PipTransitionState.EXITING_PIP;
import static com.android.wm.shell.pip.PipTransitionState.UNDEFINED;
import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
+import static com.android.wm.shell.transition.Transitions.transitTypeToString;
import android.animation.AnimationHandler;
import android.animation.Animator;
@@ -338,7 +338,7 @@ public class TvPipTransition extends PipTransitionController {
final Rect pipBounds = mPipBoundsState.getBounds();
mSurfaceTransactionHelper
.resetScale(startTransaction, pipLeash, pipBounds)
- .crop(startTransaction, pipLeash, pipBounds)
+ .cropAndPosition(startTransaction, pipLeash, pipBounds)
.shadow(startTransaction, pipLeash, false);
final SurfaceControl.Transaction transaction = mTransactionFactory.getTransaction();
@@ -420,7 +420,7 @@ public class TvPipTransition extends PipTransitionController {
mSurfaceTransactionHelper
.resetScale(finishTransaction, leash, pipBounds)
- .crop(finishTransaction, leash, pipBounds)
+ .cropAndPosition(finishTransaction, leash, pipBounds)
.shadow(finishTransaction, leash, false);
final Rect currentBounds = pipChange.getStartAbsBounds();
@@ -443,7 +443,7 @@ public class TvPipTransition extends PipTransitionController {
SurfaceControl.Transaction tx = mTransactionFactory.getTransaction();
mSurfaceTransactionHelper
.resetScale(tx, leash, pipBounds)
- .crop(tx, leash, pipBounds)
+ .cropAndPosition(tx, leash, pipBounds)
.shadow(tx, leash, false);
mShellTaskOrganizer.applyTransaction(resizePipWct);
tx.apply();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java
index d565776c9917..012dabbbb9f8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java
@@ -17,6 +17,7 @@
package com.android.wm.shell.pip2.animation;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.RectEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
@@ -27,13 +28,13 @@ import android.view.SurfaceControl;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
/**
* Animator that handles any resize related animation for PIP.
*/
-public class PipResizeAnimator extends ValueAnimator
- implements ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener{
+public class PipResizeAnimator extends ValueAnimator {
@NonNull
private final Context mContext;
@NonNull
@@ -61,9 +62,47 @@ public class PipResizeAnimator extends ValueAnimator
private final Rect mAnimatedRect = new Rect();
private final float mDelta;
- private final PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
+ private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
+ private final Animator.AnimatorListener mAnimatorListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ if (mAnimationStartCallback != null) {
+ mAnimationStartCallback.run();
+ }
+ if (mStartTx != null) {
+ setBoundsAndRotation(mStartTx, mLeash, mBaseBounds, mStartBounds, mDelta);
+ mStartTx.apply();
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ if (mFinishTx != null) {
+ setBoundsAndRotation(mFinishTx, mLeash, mBaseBounds, mEndBounds, 0f);
+ }
+ if (mAnimationEndCallback != null) {
+ mAnimationEndCallback.run();
+ }
+ }
+ };
+
+ private final ValueAnimator.AnimatorUpdateListener mAnimatorUpdateListener =
+ new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(@NonNull ValueAnimator animation) {
+ final SurfaceControl.Transaction tx =
+ mSurfaceControlTransactionFactory.getTransaction();
+ final float fraction = getAnimatedFraction();
+ final float degrees = (1.0f - fraction) * mDelta;
+ setBoundsAndRotation(tx, mLeash, mBaseBounds, mAnimatedRect, degrees);
+ tx.apply();
+ }
+ };
+
public PipResizeAnimator(@NonNull Context context,
@NonNull SurfaceControl leash,
@Nullable SurfaceControl.Transaction startTransaction,
@@ -89,8 +128,8 @@ public class PipResizeAnimator extends ValueAnimator
mRectEvaluator = new RectEvaluator(mAnimatedRect);
setObjectValues(startBounds, endBounds);
- addListener(this);
- addUpdateListener(this);
+ addListener(mAnimatorListener);
+ addUpdateListener(mAnimatorUpdateListener);
setEvaluator(mRectEvaluator);
setDuration(duration);
}
@@ -103,26 +142,6 @@ public class PipResizeAnimator extends ValueAnimator
mAnimationEndCallback = runnable;
}
- @Override
- public void onAnimationStart(@NonNull Animator animation) {
- if (mAnimationStartCallback != null) {
- mAnimationStartCallback.run();
- }
- if (mStartTx != null) {
- setBoundsAndRotation(mStartTx, mLeash, mBaseBounds, mStartBounds, mDelta);
- mStartTx.apply();
- }
- }
-
- @Override
- public void onAnimationUpdate(@NonNull ValueAnimator animation) {
- final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
- final float fraction = getAnimatedFraction();
- final float degrees = (1.0f - fraction) * mDelta;
- setBoundsAndRotation(tx, mLeash, mBaseBounds, mAnimatedRect, degrees);
- tx.apply();
- }
-
/**
* Set a proper transform matrix for a leash to move it to given bounds with a certain rotation.
*
@@ -130,7 +149,7 @@ public class PipResizeAnimator extends ValueAnimator
* @param targetBounds bounds to which we are scaling the leash.
* @param degrees degrees of rotation - counter-clockwise is positive by convention.
*/
- public static void setBoundsAndRotation(SurfaceControl.Transaction tx, SurfaceControl leash,
+ private static void setBoundsAndRotation(SurfaceControl.Transaction tx, SurfaceControl leash,
Rect baseBounds, Rect targetBounds, float degrees) {
Matrix transformTensor = new Matrix();
final float[] mMatrixTmp = new float[9];
@@ -144,19 +163,9 @@ public class PipResizeAnimator extends ValueAnimator
tx.setMatrix(leash, transformTensor, mMatrixTmp);
}
- @Override
- public void onAnimationEnd(@NonNull Animator animation) {
- if (mFinishTx != null) {
- setBoundsAndRotation(mFinishTx, mLeash, mBaseBounds, mEndBounds, 0f);
- }
- if (mAnimationEndCallback != null) {
- mAnimationEndCallback.run();
- }
+ @VisibleForTesting
+ void setSurfaceControlTransactionFactory(@NonNull
+ PipSurfaceTransactionHelper.SurfaceControlTransactionFactory factory) {
+ mSurfaceControlTransactionFactory = factory;
}
-
- @Override
- public void onAnimationCancel(@NonNull Animator animation) {}
-
- @Override
- public void onAnimationRepeat(@NonNull Animator animation) {}
}
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 839bb4e7a766..cc0e1df115c2 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
@@ -30,7 +30,6 @@ import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
-import static android.view.WindowManager.transitTypeToString;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
@@ -73,6 +72,7 @@ import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonT
import static com.android.wm.shell.transition.MixedTransitionHelper.getPipReplacingChange;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
+import static com.android.wm.shell.transition.Transitions.transitTypeToString;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
index a27c14bda15a..4feb4753096e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
@@ -24,7 +24,6 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
-import static android.view.WindowManager.transitTypeToString;
import static android.window.TransitionInfo.FLAGS_IS_NON_APP_WINDOW;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
@@ -34,6 +33,7 @@ import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITI
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_CLOSE;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_OPEN;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_OPEN;
+import static com.android.wm.shell.transition.Transitions.transitTypeToString;
import android.annotation.ColorInt;
import android.annotation.NonNull;
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 7c9cd0862b69..1d456aed5f4d 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
@@ -29,7 +29,6 @@ import static android.view.WindowManager.TRANSIT_SLEEP;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.fixScale;
-import static android.view.WindowManager.transitTypeToString;
import static android.window.TransitionInfo.FLAGS_IS_NON_APP_WINDOW;
import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED;
import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
@@ -725,7 +724,7 @@ public class Transitions implements RemoteCallable<Transitions>,
@NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl.Transaction finishT) {
info.setUnreleasedWarningCallSiteForAllSurfaces("Transitions.onTransitionReady");
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "onTransitionReady (#%d) %s: %s",
- info.getDebugId(), transitionToken, info);
+ info.getDebugId(), transitionToken, info.toString(" " /* prefix */));
int activeIdx = findByToken(mPendingTransitions, transitionToken);
if (activeIdx < 0) {
final ActiveTransition existing = mKnownTransitions.get(transitionToken);
@@ -1847,6 +1846,40 @@ public class Transitions implements RemoteCallable<Transitions>,
}
}
+ /**
+ * Like WindowManager#transitTypeToString(), but also covers known custom transition types as
+ * well.
+ */
+ public static String transitTypeToString(int transitType) {
+ if (transitType < TRANSIT_FIRST_CUSTOM) {
+ return WindowManager.transitTypeToString(transitType);
+ }
+
+ String typeStr = switch (transitType) {
+ case TRANSIT_EXIT_PIP -> "EXIT_PIP";
+ case TRANSIT_EXIT_PIP_TO_SPLIT -> "EXIT_PIP_TO_SPLIT";
+ case TRANSIT_REMOVE_PIP -> "REMOVE_PIP";
+ case TRANSIT_SPLIT_SCREEN_PAIR_OPEN -> "SPLIT_SCREEN_PAIR_OPEN";
+ case TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE -> "SPLIT_SCREEN_OPEN_TO_SIDE";
+ case TRANSIT_SPLIT_DISMISS_SNAP -> "SPLIT_DISMISS_SNAP";
+ case TRANSIT_SPLIT_DISMISS -> "SPLIT_DISMISS";
+ case TRANSIT_MAXIMIZE -> "MAXIMIZE";
+ case TRANSIT_RESTORE_FROM_MAXIMIZE -> "RESTORE_FROM_MAXIMIZE";
+ case TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP -> "DESKTOP_MODE_START_DRAG_TO_DESKTOP";
+ case TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP -> "DESKTOP_MODE_END_DRAG_TO_DESKTOP";
+ case TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP ->
+ "DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP";
+ case TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE -> "DESKTOP_MODE_TOGGLE_RESIZE";
+ case TRANSIT_RESIZE_PIP -> "RESIZE_PIP";
+ case TRANSIT_TASK_FRAGMENT_DRAG_RESIZE -> "TASK_FRAGMENT_DRAG_RESIZE";
+ case TRANSIT_SPLIT_PASSTHROUGH -> "SPLIT_PASSTHROUGH";
+ case TRANSIT_CLEANUP_PIP_EXIT -> "CLEANUP_PIP_EXIT";
+ case TRANSIT_MINIMIZE -> "MINIMIZE";
+ default -> "";
+ };
+ return typeStr + "(FIRST_CUSTOM+" + (transitType - TRANSIT_FIRST_CUSTOM) + ")";
+ }
+
private static boolean getShellTransitEnabled() {
try {
if (AppGlobals.getPackageManager().hasSystemFeature(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 3946b6173b0b..c9546731a193 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -180,12 +180,13 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
// all other cases, it is expected that the transition handler positions and crops the task
// in order to allow the handler time to animate before the task before the final
// position and crop are set.
- final boolean shouldSetTaskPositionAndCrop = mTaskDragResizer.isResizingOrAnimating();
+ final boolean shouldSetTaskVisibilityPositionAndCrop =
+ mTaskDragResizer.isResizingOrAnimating();
// Use |applyStartTransactionOnDraw| so that the transaction (that applies task crop) is
// synced with the buffer transaction (that draws the View). Both will be shown on screen
// at the same, whereas applying them independently causes flickering. See b/270202228.
relayout(taskInfo, t, t, true /* applyStartTransactionOnDraw */,
- shouldSetTaskPositionAndCrop, hasGlobalFocus);
+ shouldSetTaskVisibilityPositionAndCrop, hasGlobalFocus);
}
@VisibleForTesting
@@ -193,7 +194,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
RelayoutParams relayoutParams,
ActivityManager.RunningTaskInfo taskInfo,
boolean applyStartTransactionOnDraw,
- boolean setTaskCropAndPosition,
+ boolean shouldSetTaskVisibilityPositionAndCrop,
boolean isStatusBarVisible,
boolean isKeyguardVisibleAndOccluded,
InsetsState displayInsetsState,
@@ -206,7 +207,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
? R.dimen.freeform_decor_shadow_focused_thickness
: R.dimen.freeform_decor_shadow_unfocused_thickness;
relayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
- relayoutParams.mSetTaskPositionAndCrop = setTaskCropAndPosition;
+ relayoutParams.mSetTaskVisibilityPositionAndCrop = shouldSetTaskVisibilityPositionAndCrop;
relayoutParams.mIsCaptionVisible = taskInfo.isFreeform()
|| (isStatusBarVisible && !isKeyguardVisibleAndOccluded);
@@ -234,7 +235,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
@SuppressLint("MissingPermission")
void relayout(RunningTaskInfo taskInfo,
SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
- boolean applyStartTransactionOnDraw, boolean setTaskCropAndPosition,
+ boolean applyStartTransactionOnDraw, boolean shouldSetTaskVisibilityPositionAndCrop,
boolean hasGlobalFocus) {
final boolean isFreeform =
taskInfo.getWindowingMode() == WindowConfiguration.WINDOWING_MODE_FREEFORM;
@@ -246,7 +247,8 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
final WindowContainerTransaction wct = new WindowContainerTransaction();
updateRelayoutParams(mRelayoutParams, taskInfo, applyStartTransactionOnDraw,
- setTaskCropAndPosition, mIsStatusBarVisible, mIsKeyguardVisibleAndOccluded,
+ shouldSetTaskVisibilityPositionAndCrop, mIsStatusBarVisible,
+ mIsKeyguardVisibleAndOccluded,
mDisplayController.getInsetsState(taskInfo.displayId), hasGlobalFocus);
relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index f9307483e73d..c88ac3d19635 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -390,18 +390,25 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
@Override
void relayout(ActivityManager.RunningTaskInfo taskInfo, boolean hasGlobalFocus) {
final SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
- // The crop and position of the task should only be set when a task is fluid resizing. In
- // all other cases, it is expected that the transition handler positions and crops the task
- // in order to allow the handler time to animate before the task before the final
- // position and crop are set.
- final boolean shouldSetTaskPositionAndCrop = !DesktopModeStatus.isVeiledResizeEnabled()
- && mTaskDragResizer.isResizingOrAnimating();
+ // The visibility, crop and position of the task should only be set when a task is
+ // fluid resizing. In all other cases, it is expected that the transition handler sets
+ // those task properties to allow the handler time to animate with full control of the task
+ // leash. In general, allowing the window decoration to set any of these is likely to cause
+ // incorrect frames and flickering because relayouts from TaskListener#onTaskInfoChanged
+ // aren't synchronized with shell transition callbacks, so if they come too early it
+ // might show/hide or crop the task at a bad time.
+ // Fluid resizing is exempt from this because it intentionally doesn't use shell
+ // transitions to resize the task, so onTaskInfoChanged relayouts is the only way to make
+ // sure the crop is set correctly.
+ final boolean shouldSetTaskVisibilityPositionAndCrop =
+ !DesktopModeStatus.isVeiledResizeEnabled()
+ && mTaskDragResizer.isResizingOrAnimating();
// For headers only (i.e. in freeform): use |applyStartTransactionOnDraw| so that the
// transaction (that applies task crop) is synced with the buffer transaction (that draws
// the View). Both will be shown on screen at the same, whereas applying them independently
// causes flickering. See b/270202228.
final boolean applyTransactionOnDraw = taskInfo.isFreeform();
- relayout(taskInfo, t, t, applyTransactionOnDraw, shouldSetTaskPositionAndCrop,
+ relayout(taskInfo, t, t, applyTransactionOnDraw, shouldSetTaskVisibilityPositionAndCrop,
hasGlobalFocus);
if (!applyTransactionOnDraw) {
t.apply();
@@ -428,19 +435,19 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
void relayout(ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
- boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop,
+ boolean applyStartTransactionOnDraw, boolean shouldSetTaskVisibilityPositionAndCrop,
boolean hasGlobalFocus) {
Trace.beginSection("DesktopModeWindowDecoration#relayout");
if (taskInfo.isFreeform()) {
// The Task is in Freeform mode -> show its header in sync since it's an integral part
// of the window itself - a delayed header might cause bad UX.
relayoutInSync(taskInfo, startT, finishT, applyStartTransactionOnDraw,
- shouldSetTaskPositionAndCrop, hasGlobalFocus);
+ shouldSetTaskVisibilityPositionAndCrop, hasGlobalFocus);
} else {
// The Task is outside Freeform mode -> allow the handle view to be delayed since the
// handle is just a small addition to the window.
relayoutWithDelayedViewHost(taskInfo, startT, finishT, applyStartTransactionOnDraw,
- shouldSetTaskPositionAndCrop, hasGlobalFocus);
+ shouldSetTaskVisibilityPositionAndCrop, hasGlobalFocus);
}
Trace.endSection();
}
@@ -448,12 +455,12 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
/** Run the whole relayout phase immediately without delay. */
private void relayoutInSync(ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
- boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop,
+ boolean applyStartTransactionOnDraw, boolean shouldSetTaskVisibilityPositionAndCrop,
boolean hasGlobalFocus) {
// Clear the current ViewHost runnable as we will update the ViewHost here
clearCurrentViewHostRunnable();
updateRelayoutParamsAndSurfaces(taskInfo, startT, finishT, applyStartTransactionOnDraw,
- shouldSetTaskPositionAndCrop, hasGlobalFocus);
+ shouldSetTaskVisibilityPositionAndCrop, hasGlobalFocus);
if (mResult.mRootView != null) {
updateViewHost(mRelayoutParams, startT, mResult);
}
@@ -475,7 +482,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
*/
private void relayoutWithDelayedViewHost(ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
- boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop,
+ boolean applyStartTransactionOnDraw, boolean shouldSetTaskVisibilityPositionAndCrop,
boolean hasGlobalFocus) {
if (applyStartTransactionOnDraw) {
throw new IllegalArgumentException(
@@ -484,7 +491,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
// Clear the current ViewHost runnable as we will update the ViewHost here
clearCurrentViewHostRunnable();
updateRelayoutParamsAndSurfaces(taskInfo, startT, finishT,
- false /* applyStartTransactionOnDraw */, shouldSetTaskPositionAndCrop,
+ false /* applyStartTransactionOnDraw */, shouldSetTaskVisibilityPositionAndCrop,
hasGlobalFocus);
if (mResult.mRootView == null) {
// This means something blocks the window decor from showing, e.g. the task is hidden.
@@ -499,7 +506,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
@SuppressLint("MissingPermission")
private void updateRelayoutParamsAndSurfaces(ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
- boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop,
+ boolean applyStartTransactionOnDraw, boolean shouldSetTaskVisibilityPositionAndCrop,
boolean hasGlobalFocus) {
Trace.beginSection("DesktopModeWindowDecoration#updateRelayoutParamsAndSurfaces");
@@ -524,9 +531,9 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
final boolean inFullImmersive = mDesktopRepository
.isTaskInFullImmersiveState(taskInfo.taskId);
updateRelayoutParams(mRelayoutParams, mContext, taskInfo, applyStartTransactionOnDraw,
- shouldSetTaskPositionAndCrop, mIsStatusBarVisible, mIsKeyguardVisibleAndOccluded,
- inFullImmersive, mDisplayController.getInsetsState(taskInfo.displayId),
- hasGlobalFocus);
+ shouldSetTaskVisibilityPositionAndCrop, mIsStatusBarVisible,
+ mIsKeyguardVisibleAndOccluded, inFullImmersive,
+ mDisplayController.getInsetsState(taskInfo.displayId), hasGlobalFocus);
final WindowDecorLinearLayout oldRootView = mResult.mRootView;
final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
@@ -852,7 +859,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
Context context,
ActivityManager.RunningTaskInfo taskInfo,
boolean applyStartTransactionOnDraw,
- boolean shouldSetTaskPositionAndCrop,
+ boolean shouldSetTaskVisibilityPositionAndCrop,
boolean isStatusBarVisible,
boolean isKeyguardVisibleAndOccluded,
boolean inFullImmersiveMode,
@@ -948,7 +955,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
: R.dimen.freeform_decor_shadow_unfocused_thickness;
}
relayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
- relayoutParams.mSetTaskPositionAndCrop = shouldSetTaskPositionAndCrop;
+ relayoutParams.mSetTaskVisibilityPositionAndCrop = shouldSetTaskVisibilityPositionAndCrop;
// The configuration used to layout the window decoration. A copy is made instead of using
// the original reference so that the configuration isn't mutated on config changes and
@@ -1089,13 +1096,13 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
if (mAppIconBitmap != null && mAppName != null) {
return;
}
- final ComponentName baseActivity = mTaskInfo.baseActivity;
- if (baseActivity == null) {
- Slog.e(TAG, "Base activity component not found in task");
+ if (mTaskInfo.baseIntent == null) {
+ Slog.e(TAG, "Base intent not found in task");
return;
}
final PackageManager pm = mUserContext.getPackageManager();
- final ActivityInfo activityInfo = pm.getActivityInfo(baseActivity, 0 /* flags */);
+ final ActivityInfo activityInfo =
+ pm.getActivityInfo(mTaskInfo.baseIntent.getComponent(), 0 /* flags */);
final IconProvider provider = new IconProvider(mContext);
final Drawable appIconDrawable = provider.getIcon(activityInfo);
final Drawable badgedAppIconDrawable = pm.getUserBadgedIcon(appIconDrawable,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index f97dfb89bc0d..b016c755e323 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -249,7 +249,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
if (!mTaskInfo.isVisible) {
releaseViews(wct);
- finishT.hide(mTaskSurface);
+ if (params.mSetTaskVisibilityPositionAndCrop) {
+ finishT.hide(mTaskSurface);
+ }
return;
}
@@ -422,7 +424,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
private void updateTaskSurface(RelayoutParams params, SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT, RelayoutResult<T> outResult) {
- if (params.mSetTaskPositionAndCrop) {
+ if (params.mSetTaskVisibilityPositionAndCrop) {
final Point taskPosition = mTaskInfo.positionInParent;
startT.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight);
finishT.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight)
@@ -437,9 +439,13 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
shadowRadius =
loadDimension(mDecorWindowContext.getResources(), params.mShadowRadiusId);
}
- startT.setShadowRadius(mTaskSurface, shadowRadius).show(mTaskSurface);
+ startT.setShadowRadius(mTaskSurface, shadowRadius);
finishT.setShadowRadius(mTaskSurface, shadowRadius);
+ if (params.mSetTaskVisibilityPositionAndCrop) {
+ startT.show(mTaskSurface);
+ }
+
if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
if (!DesktopModeStatus.isVeiledResizeEnabled()) {
// When fluid resize is enabled, add a background to freeform tasks
@@ -758,7 +764,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
Configuration mWindowDecorConfig;
boolean mApplyStartTransactionOnDraw;
- boolean mSetTaskPositionAndCrop;
+ boolean mSetTaskVisibilityPositionAndCrop;
boolean mHasGlobalFocus;
void reset() {
@@ -777,7 +783,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
mIsCaptionVisible = false;
mApplyStartTransactionOnDraw = false;
- mSetTaskPositionAndCrop = false;
+ mSetTaskVisibilityPositionAndCrop = false;
mWindowDecorConfig = null;
mHasGlobalFocus = false;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModel.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModel.kt
index ff418c6daa02..e43c3a613157 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModel.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModel.kt
@@ -21,10 +21,13 @@ import android.app.ActivityManager.RunningTaskInfo
import android.content.Context
import android.graphics.Rect
import android.util.SparseArray
+import android.window.DisplayAreaInfo
+import android.window.WindowContainerTransaction
import androidx.core.util.valueIterator
import com.android.internal.annotations.VisibleForTesting
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.ShellTaskOrganizer
+import com.android.wm.shell.common.DisplayChangeController
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.desktopmode.DesktopRepository
@@ -45,10 +48,16 @@ class DesktopTilingDecorViewModel(
private val toggleResizeDesktopTaskTransitionHandler: ToggleResizeDesktopTaskTransitionHandler,
private val returnToDragStartAnimator: ReturnToDragStartAnimator,
private val taskRepository: DesktopRepository,
-) {
+) : DisplayChangeController.OnDisplayChangingListener {
@VisibleForTesting
var tilingTransitionHandlerByDisplayId = SparseArray<DesktopTilingWindowDecoration>()
+ init {
+ // TODO(b/374309287): Move this interface implementation to
+ // [DesktopModeWindowDecorViewModel] when the migration is done.
+ displayController.addDisplayChangingController(this)
+ }
+
fun snapToHalfScreen(
taskInfo: ActivityManager.RunningTaskInfo,
desktopModeWindowDecoration: DesktopModeWindowDecoration,
@@ -102,7 +111,20 @@ class DesktopTilingDecorViewModel(
fun onUserChange() {
for (tilingHandler in tilingTransitionHandlerByDisplayId.valueIterator()) {
- tilingHandler.onUserChange()
+ tilingHandler.resetTilingSession()
}
}
+
+ override fun onDisplayChange(
+ displayId: Int,
+ fromRotation: Int,
+ toRotation: Int,
+ newDisplayAreaInfo: DisplayAreaInfo?,
+ t: WindowContainerTransaction?,
+ ) {
+ // Exit if the rotation hasn't changed or is changed by 180 degrees. [fromRotation] and
+ // [toRotation] can be one of the [@Surface.Rotation] values.
+ if ((fromRotation % 2 == toRotation % 2)) return
+ tilingTransitionHandlerByDisplayId.get(displayId)?.resetTilingSession()
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
index 9bf1304f2b39..209eb5e501b2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
@@ -23,6 +23,7 @@ import android.graphics.Rect
import android.graphics.Region
import android.os.Binder
import android.view.LayoutInflater
+import android.view.RoundedCorner
import android.view.SurfaceControl
import android.view.SurfaceControlViewHost
import android.view.View
@@ -53,12 +54,14 @@ class DesktopTilingDividerWindowManager(
private val transitionHandler: DesktopTilingWindowDecoration,
private val transactionSupplier: Supplier<SurfaceControl.Transaction>,
private var dividerBounds: Rect,
+ private val displayContext: Context,
) : WindowlessWindowManager(config, leash, null), DividerMoveCallback, View.OnLayoutChangeListener {
private lateinit var viewHost: SurfaceControlViewHost
private var tilingDividerView: TilingDividerView? = null
private var dividerShown = false
private var handleRegionWidth: Int = -1
private var setTouchRegion = true
+ private val maxRoundedCornerRadius = getMaxRoundedCornerRadius()
/**
* Gets bounds of divider window with screen based coordinate on the param Rect.
@@ -93,7 +96,11 @@ class DesktopTilingDividerWindowManager(
getDividerBounds(tmpDividerBounds)
dividerView.setup(this, tmpDividerBounds)
t.setRelativeLayer(leash, relativeLeash, 1)
- .setPosition(leash, dividerBounds.left.toFloat(), dividerBounds.top.toFloat())
+ .setPosition(
+ leash,
+ dividerBounds.left.toFloat() - maxRoundedCornerRadius,
+ dividerBounds.top.toFloat(),
+ )
.show(leash)
syncQueue.runInSync { transaction ->
transaction.merge(t)
@@ -144,7 +151,7 @@ class DesktopTilingDividerWindowManager(
*/
override fun onDividerMove(pos: Int): Boolean {
val t = transactionSupplier.get()
- t.setPosition(leash, pos.toFloat(), dividerBounds.top.toFloat())
+ t.setPosition(leash, pos.toFloat() - maxRoundedCornerRadius, dividerBounds.top.toFloat())
val dividerWidth = dividerBounds.width()
dividerBounds.set(pos, dividerBounds.top, pos + dividerWidth, dividerBounds.bottom)
return transitionHandler.onDividerHandleMoved(dividerBounds, t)
@@ -157,7 +164,7 @@ class DesktopTilingDividerWindowManager(
override fun onDividerMovedEnd(pos: Int) {
setSlippery(true)
val t = transactionSupplier.get()
- t.setPosition(leash, pos.toFloat(), dividerBounds.top.toFloat())
+ t.setPosition(leash, pos.toFloat() - maxRoundedCornerRadius, dividerBounds.top.toFloat())
val dividerWidth = dividerBounds.width()
dividerBounds.set(pos, dividerBounds.top, pos + dividerWidth, dividerBounds.bottom)
transitionHandler.onDividerHandleDragEnd(dividerBounds, t)
@@ -166,7 +173,7 @@ class DesktopTilingDividerWindowManager(
private fun getWindowManagerParams(): WindowManager.LayoutParams {
val lp =
WindowManager.LayoutParams(
- dividerBounds.width(),
+ dividerBounds.width() + 2 * maxRoundedCornerRadius,
dividerBounds.height(),
TYPE_DOCK_DIVIDER,
FLAG_NOT_FOCUSABLE or
@@ -225,4 +232,15 @@ class DesktopTilingDividerWindowManager(
}
viewHost.relayout(lp)
}
+
+ private fun getMaxRoundedCornerRadius(): Int {
+ val display = displayContext.display
+ return listOf(
+ RoundedCorner.POSITION_TOP_LEFT,
+ RoundedCorner.POSITION_TOP_RIGHT,
+ RoundedCorner.POSITION_BOTTOM_RIGHT,
+ RoundedCorner.POSITION_BOTTOM_LEFT,
+ )
+ .maxOf { position -> display.getRoundedCorner(position)?.getRadius() ?: 0 }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt
index a7087aec3bb5..c46767c3a51d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt
@@ -195,6 +195,7 @@ class DesktopTilingWindowDecoration(
val builder = SurfaceControl.Builder()
rootTdaOrganizer.attachToDisplayArea(displayId, builder)
val leash = builder.setName(TILING_DIVIDER_TAG).setContainerLayer().build()
+ val displayContext = displayController.getDisplayContext(displayId) ?: return null
val tilingManager =
displayLayout?.let {
dividerBounds = inflateDividerBounds(it)
@@ -207,6 +208,7 @@ class DesktopTilingWindowDecoration(
this,
transactionSupplier,
dividerBounds,
+ displayContext,
)
}
// a leash to present the divider on top of, without re-parenting.
@@ -483,7 +485,7 @@ class DesktopTilingWindowDecoration(
}
}
- fun onUserChange() {
+ fun resetTilingSession() {
if (leftTaskResizingHelper != null) {
removeTask(leftTaskResizingHelper, taskVanished = false, shouldDelayUpdate = true)
leftTaskResizingHelper = null
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt
index f8113c219bd1..89229051941c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt
@@ -118,7 +118,7 @@ class TilingDividerView : FrameLayout, View.OnTouchListener, DragDetector.Motion
val dividerSize = resources.getDimensionPixelSize(R.dimen.split_divider_bar_width)
val backgroundLeft = (width - dividerSize) / 2
val backgroundTop = 0
- val backgroundRight = left + dividerSize
+ val backgroundRight = backgroundLeft + dividerSize
val backgroundBottom = height
backgroundRect.set(backgroundLeft, backgroundTop, backgroundRight, backgroundBottom)
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 72d4dc6ffac9..13a8518ae8ed 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -700,7 +700,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
eq(tInfo), eq(st), eq(ft), eq(callback));
mBackTransitionHandler.onAnimationFinished();
- final TransitionInfo.Change openToClose = createAppChange(openTaskId, TRANSIT_CLOSE,
+ final TransitionInfo.Change openToClose = createAppChangeFromChange(open, TRANSIT_CLOSE,
FLAG_BACK_GESTURE_ANIMATED);
tInfo2 = createTransitionInfo(TRANSIT_CLOSE_PREPARE_BACK_NAVIGATION, openToClose);
mBackTransitionHandler.mClosePrepareTransition = mock(IBinder.class);
@@ -830,6 +830,16 @@ public class BackAnimationControllerTest extends ShellTestCase {
return change;
}
+ private TransitionInfo.Change createAppChangeFromChange(
+ TransitionInfo.Change originalChange, @TransitionInfo.TransitionMode int mode,
+ @TransitionInfo.ChangeFlags int flags) {
+ final TransitionInfo.Change change = new TransitionInfo.Change(
+ originalChange.getTaskInfo().token, originalChange.getLeash());
+ change.setMode(mode);
+ change.setFlags(flags);
+ return change;
+ }
+
private static TransitionInfo createTransitionInfo(
@WindowManager.TransitionType int type, TransitionInfo.Change ... changes) {
final TransitionInfo info = new TransitionInfo(type, 0);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt
index 868883d12ac0..df061e368071 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt
@@ -39,9 +39,12 @@ import androidx.test.filters.SmallTest
import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE
import com.android.internal.jank.InteractionJankMonitor
import com.android.window.flags.Flags
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.TestRunningTaskInfoBuilder
+import com.android.wm.shell.desktopmode.DesktopMixedTransitionHandler.PendingMixedTransition
import com.android.wm.shell.freeform.FreeformTaskTransitionHandler
+import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.Transitions
import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertFalse
@@ -51,7 +54,9 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.kotlin.any
import org.mockito.kotlin.anyOrNull
@@ -80,6 +85,8 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() {
@Mock lateinit var interactionJankMonitor: InteractionJankMonitor
@Mock lateinit var mockHandler: Handler
@Mock lateinit var closingTaskLeash: SurfaceControl
+ @Mock lateinit var shellInit: ShellInit
+ @Mock lateinit var rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
private lateinit var mixedHandler: DesktopMixedTransitionHandler
@@ -94,7 +101,9 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() {
closeDesktopTaskTransitionHandler,
desktopImmersiveController,
interactionJankMonitor,
- mockHandler
+ mockHandler,
+ shellInit,
+ rootTaskDisplayAreaOrganizer,
)
}
@@ -238,8 +247,10 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() {
}
@Test
- @DisableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
- fun startLaunchTransition_immersiveMixDisabled_doesNotUseMixedHandler() {
+ @DisableFlags(
+ Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP,
+ Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS)
+ fun startLaunchTransition_immersiveAndAppLaunchFlagsDisabled_doesNotUseMixedHandler() {
val wct = WindowContainerTransaction()
val task = createTask(WINDOWING_MODE_FREEFORM)
whenever(transitions.startTransition(eq(TRANSIT_OPEN), eq(wct), anyOrNull()))
@@ -274,6 +285,24 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() {
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS)
+ fun startLaunchTransition_desktopAppLaunchEnabled_usesMixedHandler() {
+ val wct = WindowContainerTransaction()
+ val task = createTask(WINDOWING_MODE_FREEFORM)
+ whenever(transitions.startTransition(eq(TRANSIT_OPEN), eq(wct), anyOrNull()))
+ .thenReturn(Binder())
+
+ mixedHandler.startLaunchTransition(
+ transitionType = TRANSIT_OPEN,
+ wct = wct,
+ taskId = task.taskId,
+ exitingImmersiveTask = null
+ )
+
+ verify(transitions).startTransition(TRANSIT_OPEN, wct, mixedHandler)
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
fun startAndAnimateLaunchTransition_withoutImmersiveChange_dispatchesAllChangesToLeftOver() {
val wct = WindowContainerTransaction()
@@ -355,6 +384,134 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() {
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS)
+ fun startAndAnimateLaunchTransition_noMinimizeChange_doesNotReparentMinimizeChange() {
+ val wct = WindowContainerTransaction()
+ val launchingTask = createTask(WINDOWING_MODE_FREEFORM)
+ val launchTaskChange = createChange(launchingTask)
+ val transition = Binder()
+ whenever(transitions.startTransition(eq(TRANSIT_OPEN), eq(wct), anyOrNull()))
+ .thenReturn(transition)
+
+ mixedHandler.startLaunchTransition(
+ transitionType = TRANSIT_OPEN,
+ wct = wct,
+ taskId = launchingTask.taskId,
+ minimizingTaskId = null,
+ )
+ mixedHandler.startAnimation(
+ transition,
+ createTransitionInfo(
+ TRANSIT_OPEN,
+ listOf(launchTaskChange)
+ ),
+ SurfaceControl.Transaction(),
+ SurfaceControl.Transaction(),
+ ) { }
+
+ verify(rootTaskDisplayAreaOrganizer, times(0))
+ .reparentToDisplayArea(anyInt(), any(), any())
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS)
+ fun startAndAnimateLaunchTransition_withMinimizeChange_reparentsMinimizeChange() {
+ val wct = WindowContainerTransaction()
+ val launchingTask = createTask(WINDOWING_MODE_FREEFORM)
+ val minimizingTask = createTask(WINDOWING_MODE_FREEFORM)
+ val launchTaskChange = createChange(launchingTask)
+ val minimizeChange = createChange(minimizingTask)
+ val transition = Binder()
+ whenever(transitions.startTransition(eq(TRANSIT_OPEN), eq(wct), anyOrNull()))
+ .thenReturn(transition)
+
+ mixedHandler.startLaunchTransition(
+ transitionType = TRANSIT_OPEN,
+ wct = wct,
+ taskId = launchingTask.taskId,
+ minimizingTaskId = minimizingTask.taskId,
+ )
+ mixedHandler.startAnimation(
+ transition,
+ createTransitionInfo(
+ TRANSIT_OPEN,
+ listOf(launchTaskChange, minimizeChange)
+ ),
+ SurfaceControl.Transaction(),
+ SurfaceControl.Transaction(),
+ ) { }
+
+ verify(rootTaskDisplayAreaOrganizer).reparentToDisplayArea(
+ anyInt(), eq(minimizeChange.leash), any())
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS)
+ fun addPendingAndAnimateLaunchTransition_noMinimizeChange_doesNotReparentMinimizeChange() {
+ val wct = WindowContainerTransaction()
+ val launchingTask = createTask(WINDOWING_MODE_FREEFORM)
+ val launchTaskChange = createChange(launchingTask)
+ val transition = Binder()
+ whenever(transitions.startTransition(eq(TRANSIT_OPEN), eq(wct), anyOrNull()))
+ .thenReturn(transition)
+
+ mixedHandler.addPendingMixedTransition(
+ PendingMixedTransition.Launch(
+ transition = transition,
+ launchingTask = launchingTask.taskId,
+ minimizingTask = null,
+ exitingImmersiveTask = null,
+ )
+ )
+ mixedHandler.startAnimation(
+ transition,
+ createTransitionInfo(
+ TRANSIT_OPEN,
+ listOf(launchTaskChange)
+ ),
+ SurfaceControl.Transaction(),
+ SurfaceControl.Transaction(),
+ ) { }
+
+ verify(rootTaskDisplayAreaOrganizer, times(0))
+ .reparentToDisplayArea(anyInt(), any(), any())
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS)
+ fun addPendingAndAnimateLaunchTransition_withMinimizeChange_reparentsMinimizeChange() {
+ val wct = WindowContainerTransaction()
+ val launchingTask = createTask(WINDOWING_MODE_FREEFORM)
+ val minimizingTask = createTask(WINDOWING_MODE_FREEFORM)
+ val launchTaskChange = createChange(launchingTask)
+ val minimizeChange = createChange(minimizingTask)
+ val transition = Binder()
+ whenever(transitions.startTransition(eq(TRANSIT_OPEN), eq(wct), anyOrNull()))
+ .thenReturn(transition)
+
+ mixedHandler.addPendingMixedTransition(
+ PendingMixedTransition.Launch(
+ transition = transition,
+ launchingTask = launchingTask.taskId,
+ minimizingTask = minimizingTask.taskId,
+ exitingImmersiveTask = null,
+ )
+ )
+ mixedHandler.startAnimation(
+ transition,
+ createTransitionInfo(
+ TRANSIT_OPEN,
+ listOf(launchTaskChange, minimizeChange)
+ ),
+ SurfaceControl.Transaction(),
+ SurfaceControl.Transaction(),
+ ) { }
+
+ verify(rootTaskDisplayAreaOrganizer).reparentToDisplayArea(
+ anyInt(), eq(minimizeChange.leash), any())
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
fun startAndAnimateLaunchTransition_removesPendingMixedTransition() {
val wct = WindowContainerTransaction()
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 fc89b0e127ae..b157d557c1d8 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
@@ -1413,7 +1413,8 @@ class DesktopTasksControllerTest : ShellTestCase() {
eq(TRANSIT_TO_FRONT),
any(),
eq(freeformTasks[0].taskId),
- anyOrNull()
+ anyOrNull(),
+ anyOrNull(),
)).thenReturn(Binder())
controller.moveTaskToFront(freeformTasks[0], remoteTransition = null)
@@ -1471,7 +1472,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
val task = createTaskInfo(1001)
whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(null)
whenever(desktopMixedTransitionHandler
- .startLaunchTransition(eq(TRANSIT_OPEN), any(), eq(task.taskId), anyOrNull()))
+ .startLaunchTransition(eq(TRANSIT_OPEN), any(), eq(task.taskId), anyOrNull(), anyOrNull()))
.thenReturn(Binder())
controller.moveTaskToFront(task.taskId, remoteTransition = null)
@@ -3692,7 +3693,8 @@ class DesktopTasksControllerTest : ShellTestCase() {
runOnTransitionStart = runOnStartTransit,
))
whenever(desktopMixedTransitionHandler
- .startLaunchTransition(any(), any(), anyInt(), anyOrNull())).thenReturn(transition)
+ .startLaunchTransition(any(), any(), anyInt(), anyOrNull(), anyOrNull()))
+ .thenReturn(transition)
controller.moveTaskToFront(task.taskId, remoteTransition = null)
@@ -3713,7 +3715,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
runOnTransitionStart = runOnStartTransit,
))
whenever(desktopMixedTransitionHandler
- .startLaunchTransition(any(), any(), eq(task.taskId), anyOrNull()))
+ .startLaunchTransition(any(), any(), eq(task.taskId), anyOrNull(), anyOrNull()))
.thenReturn(transition)
controller.moveTaskToFront(task.taskId, remoteTransition = null)
@@ -4102,7 +4104,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
val arg: ArgumentCaptor<WindowContainerTransaction> =
ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
verify(desktopMixedTransitionHandler)
- .startLaunchTransition(eq(type), capture(arg), anyInt(), anyOrNull())
+ .startLaunchTransition(eq(type), capture(arg), anyInt(), anyOrNull(), anyOrNull())
return arg.value
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt
index 54198876955a..7dbadc9d9083 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt
@@ -68,7 +68,6 @@ import org.mockito.kotlin.whenever
@SmallTest
@RunWith(AndroidTestingRunner::class)
@OptIn(ExperimentalCoroutinesApi::class)
-@Ignore("b/374328725")
class AppHandleEducationControllerTest : ShellTestCase() {
@JvmField
@Rule
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index e74c804d4f40..bcb7461bfae7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -280,7 +280,7 @@ public class PipTaskOrganizerTest extends ShellTestCase {
private void preparePipSurfaceTransactionHelper() {
doReturn(mMockPipSurfaceTransactionHelper).when(mMockPipSurfaceTransactionHelper)
- .crop(any(), any(), any());
+ .cropAndPosition(any(), any(), any());
doReturn(mMockPipSurfaceTransactionHelper).when(mMockPipSurfaceTransactionHelper)
.resetScale(any(), any(), any());
doReturn(mMockPipSurfaceTransactionHelper).when(mMockPipSurfaceTransactionHelper)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipResizeAnimatorTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipResizeAnimatorTest.java
new file mode 100644
index 000000000000..0adb50b81896
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipResizeAnimatorTest.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.pip2.animation;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+import static org.mockito.kotlin.MatchersKt.eq;
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.SurfaceControl;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
+
+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;
+
+/**
+ * Unit test against {@link PipResizeAnimator}.
+ */
+@SmallTest
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner.class)
+public class PipResizeAnimatorTest {
+
+ private static final float FLOAT_COMPARISON_DELTA = 0.001f;
+
+ @Mock private Context mMockContext;
+
+ @Mock private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mMockFactory;
+
+ @Mock private SurfaceControl.Transaction mMockTransaction;
+
+ @Mock private SurfaceControl.Transaction mMockStartTransaction;
+
+ @Mock private SurfaceControl.Transaction mMockFinishTransaction;
+
+ @Mock private Runnable mMockStartCallback;
+
+ @Mock private Runnable mMockEndCallback;
+
+ private PipResizeAnimator mPipResizeAnimator;
+ private Rect mBaseBounds;
+ private Rect mStartBounds;
+ private Rect mEndBounds;
+ private SurfaceControl mTestLeash;
+ private ArgumentCaptor<Matrix> mArgumentCaptor;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mMockFactory.getTransaction()).thenReturn(mMockTransaction);
+ when(mMockTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
+ .thenReturn(mMockTransaction);
+ when(mMockStartTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
+ .thenReturn(mMockStartTransaction);
+ when(mMockFinishTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
+ .thenReturn(mMockFinishTransaction);
+
+ mArgumentCaptor = ArgumentCaptor.forClass(Matrix.class);
+ mTestLeash = new SurfaceControl.Builder()
+ .setContainerLayer()
+ .setName("PipResizeAnimatorTest")
+ .setCallsite("PipResizeAnimatorTest")
+ .build();
+ }
+
+ @Test
+ public void setAnimationStartCallback_resize_callbackStartCallback() {
+ mBaseBounds = new Rect(100, 100, 500, 500);
+ mStartBounds = new Rect(200, 200, 1_000, 1_000);
+ mEndBounds = new Rect(mBaseBounds);
+ final int duration = 10;
+ final float delta = 0;
+ mPipResizeAnimator = new PipResizeAnimator(mMockContext, mTestLeash,
+ mMockStartTransaction, mMockFinishTransaction,
+ mBaseBounds, mStartBounds, mEndBounds,
+ duration, delta);
+
+ mPipResizeAnimator.setAnimationStartCallback(mMockStartCallback);
+ mPipResizeAnimator.setAnimationEndCallback(mMockEndCallback);
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ mPipResizeAnimator.start();
+ mPipResizeAnimator.pause();
+ });
+
+ verify(mMockStartCallback).run();
+ verifyZeroInteractions(mMockEndCallback);
+ }
+
+ @Test
+ public void setAnimationEndCallback_resize_callbackStartAndEndCallback() {
+ mBaseBounds = new Rect(100, 100, 500, 500);
+ mStartBounds = new Rect(200, 200, 1_000, 1_000);
+ mEndBounds = new Rect(mBaseBounds);
+ final int duration = 10;
+ final float delta = 0;
+ mPipResizeAnimator = new PipResizeAnimator(mMockContext, mTestLeash,
+ mMockStartTransaction, mMockFinishTransaction,
+ mBaseBounds, mStartBounds, mEndBounds,
+ duration, delta);
+
+ mPipResizeAnimator.setAnimationStartCallback(mMockStartCallback);
+ mPipResizeAnimator.setAnimationEndCallback(mMockEndCallback);
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ mPipResizeAnimator.start();
+ mPipResizeAnimator.end();
+ });
+
+ verify(mMockStartCallback).run();
+ verify(mMockEndCallback).run();
+ }
+
+ @Test
+ public void onAnimationEnd_resizeDown_sizeChanged() {
+ // Resize from 800x800 to 400x400, eg. resize down
+ mBaseBounds = new Rect(100, 100, 500, 500);
+ mStartBounds = new Rect(200, 200, 1_000, 1_000);
+ mEndBounds = new Rect(mBaseBounds);
+ final int duration = 10;
+ final float delta = 0;
+ final float[] matrix = new float[9];
+ mPipResizeAnimator = new PipResizeAnimator(mMockContext, mTestLeash,
+ mMockStartTransaction, mMockFinishTransaction,
+ mBaseBounds, mStartBounds, mEndBounds,
+ duration, delta);
+ mPipResizeAnimator.setSurfaceControlTransactionFactory(mMockFactory);
+
+ mPipResizeAnimator.setAnimationStartCallback(mMockStartCallback);
+ mPipResizeAnimator.setAnimationEndCallback(mMockEndCallback);
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ mPipResizeAnimator.start();
+ clearInvocations(mMockTransaction);
+ mPipResizeAnimator.end();
+ });
+
+ // Start transaction scales down from its final state
+ verify(mMockStartTransaction).setMatrix(eq(mTestLeash), mArgumentCaptor.capture(), any());
+ mArgumentCaptor.getValue().getValues(matrix);
+ assertEquals(matrix[Matrix.MSCALE_X],
+ mStartBounds.width() / (float) mEndBounds.width(), FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MSCALE_Y],
+ mStartBounds.height() / (float) mEndBounds.height(), FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MTRANS_X], mStartBounds.left, FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MTRANS_Y], mStartBounds.top, FLOAT_COMPARISON_DELTA);
+
+ // Final animation transaction scales to 1 and puts the leash at final position
+ verify(mMockTransaction).setMatrix(eq(mTestLeash), mArgumentCaptor.capture(), any());
+ mArgumentCaptor.getValue().getValues(matrix);
+ assertEquals(matrix[Matrix.MSCALE_X], 1f, FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MSCALE_Y], 1f, FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MTRANS_X], mEndBounds.left, FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MTRANS_Y], mEndBounds.top, FLOAT_COMPARISON_DELTA);
+
+ // Finish transaction resets scale and puts the leash at final position
+ verify(mMockFinishTransaction).setMatrix(eq(mTestLeash), mArgumentCaptor.capture(), any());
+ mArgumentCaptor.getValue().getValues(matrix);
+ assertEquals(matrix[Matrix.MSCALE_X], 1f, FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MSCALE_Y], 1f, FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MTRANS_X], mEndBounds.left, FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MTRANS_Y], mEndBounds.top, FLOAT_COMPARISON_DELTA);
+ }
+
+ @Test
+ public void onAnimationEnd_resizeUp_sizeChanged() {
+ // Resize from 400x400 to 800x800, eg. resize up
+ mBaseBounds = new Rect(200, 200, 1_000, 1_000);
+ mStartBounds = new Rect(100, 100, 500, 500);
+ mEndBounds = new Rect(mBaseBounds);
+ final int duration = 10;
+ final float delta = 0;
+ final float[] matrix = new float[9];
+ mPipResizeAnimator = new PipResizeAnimator(mMockContext, mTestLeash,
+ mMockStartTransaction, mMockFinishTransaction,
+ mBaseBounds, mStartBounds, mEndBounds,
+ duration, delta);
+ mPipResizeAnimator.setSurfaceControlTransactionFactory(mMockFactory);
+
+ mPipResizeAnimator.setAnimationStartCallback(mMockStartCallback);
+ mPipResizeAnimator.setAnimationEndCallback(mMockEndCallback);
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ mPipResizeAnimator.start();
+ clearInvocations(mMockTransaction);
+ mPipResizeAnimator.end();
+ });
+
+ // Start transaction scales up from its final state
+ verify(mMockStartTransaction).setMatrix(eq(mTestLeash), mArgumentCaptor.capture(), any());
+ mArgumentCaptor.getValue().getValues(matrix);
+ assertEquals(matrix[Matrix.MSCALE_X],
+ mStartBounds.width() / (float) mEndBounds.width(), FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MSCALE_Y],
+ mStartBounds.height() / (float) mEndBounds.height(), FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MTRANS_X], mStartBounds.left, FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MTRANS_Y], mStartBounds.top, FLOAT_COMPARISON_DELTA);
+
+ // Final animation transaction scales to 1 and puts the leash at final position
+ verify(mMockTransaction).setMatrix(eq(mTestLeash), mArgumentCaptor.capture(), any());
+ mArgumentCaptor.getValue().getValues(matrix);
+ assertEquals(matrix[Matrix.MSCALE_X], 1f, FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MSCALE_Y], 1f, FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MTRANS_X], mEndBounds.left, FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MTRANS_Y], mEndBounds.top, FLOAT_COMPARISON_DELTA);
+
+ // Finish transaction resets scale and puts the leash at final position
+ verify(mMockFinishTransaction).setMatrix(eq(mTestLeash), mArgumentCaptor.capture(), any());
+ mArgumentCaptor.getValue().getValues(matrix);
+ assertEquals(matrix[Matrix.MSCALE_X], 1f, FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MSCALE_Y], 1f, FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MTRANS_X], mEndBounds.left, FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MTRANS_Y], mEndBounds.top, FLOAT_COMPARISON_DELTA);
+ }
+
+ @Test
+ public void onAnimationEnd_withInitialDelta_rotateToZeroDegree() {
+ mBaseBounds = new Rect(200, 200, 1_000, 1_000);
+ mStartBounds = new Rect(100, 100, 500, 500);
+ mEndBounds = new Rect(mBaseBounds);
+ final int duration = 10;
+ final float delta = 45;
+ final float[] matrix = new float[9];
+ mPipResizeAnimator = new PipResizeAnimator(mMockContext, mTestLeash,
+ mMockStartTransaction, mMockFinishTransaction,
+ mBaseBounds, mStartBounds, mEndBounds,
+ duration, delta);
+ mPipResizeAnimator.setSurfaceControlTransactionFactory(mMockFactory);
+
+ mPipResizeAnimator.setAnimationStartCallback(mMockStartCallback);
+ mPipResizeAnimator.setAnimationEndCallback(mMockEndCallback);
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ mPipResizeAnimator.start();
+ clearInvocations(mMockTransaction);
+ mPipResizeAnimator.end();
+ });
+
+ // Final animation transaction sets skew to zero
+ verify(mMockTransaction).setMatrix(eq(mTestLeash), mArgumentCaptor.capture(), any());
+ mArgumentCaptor.getValue().getValues(matrix);
+ assertEquals(matrix[Matrix.MSKEW_X], 0f, FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MSKEW_Y], 0f, FLOAT_COMPARISON_DELTA);
+
+ // Finish transaction sets skew to zero
+ verify(mMockFinishTransaction).setMatrix(eq(mTestLeash), mArgumentCaptor.capture(), any());
+ mArgumentCaptor.getValue().getValues(matrix);
+ assertEquals(matrix[Matrix.MSKEW_X], 0f, FLOAT_COMPARISON_DELTA);
+ assertEquals(matrix[Matrix.MSKEW_Y], 0f, FLOAT_COMPARISON_DELTA);
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index cb7fadee9822..8e0434cb28f7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -218,8 +218,6 @@ public class WindowDecorationTests extends ShellTestCase {
verify(captionContainerSurfaceBuilder, never()).build();
verify(mMockSurfaceControlViewHostFactory, never()).create(any(), any(), any());
- verify(mMockSurfaceControlFinishT).hide(mMockTaskSurface);
-
assertNull(mRelayoutResult.mRootView);
}
@@ -281,8 +279,6 @@ public class WindowDecorationTests extends ShellTestCase {
verify(mMockSurfaceControlStartT).setCornerRadius(mMockTaskSurface, CORNER_RADIUS);
verify(mMockSurfaceControlFinishT).setCornerRadius(mMockTaskSurface, CORNER_RADIUS);
- verify(mMockSurfaceControlStartT)
- .show(mMockTaskSurface);
verify(mMockSurfaceControlStartT).setShadowRadius(mMockTaskSurface, 10);
assertEquals(300, mRelayoutResult.mWidth);
@@ -863,7 +859,7 @@ public class WindowDecorationTests extends ShellTestCase {
final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
- mRelayoutParams.mSetTaskPositionAndCrop = false;
+ mRelayoutParams.mSetTaskVisibilityPositionAndCrop = false;
windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
verify(mMockSurfaceControlStartT, never()).setWindowCrop(
@@ -891,7 +887,7 @@ public class WindowDecorationTests extends ShellTestCase {
taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
- mRelayoutParams.mSetTaskPositionAndCrop = true;
+ mRelayoutParams.mSetTaskVisibilityPositionAndCrop = true;
windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
verify(mMockSurfaceControlStartT).setWindowCrop(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModelTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModelTest.kt
index 52e93bb87ea3..80ad1df44a1b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModelTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModelTest.kt
@@ -36,6 +36,7 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
@@ -145,7 +146,7 @@ class DesktopTilingDecorViewModelTest : ShellTestCase() {
}
@Test
- fun userChange_starting_allTilingSessionsShouldBeDestroyed() {
+ fun onUserChange_allTilingSessionsShouldBeDestroyed() {
desktopTilingDecorViewModel.tilingTransitionHandlerByDisplayId.put(
1,
desktopTilingDecoration,
@@ -157,7 +158,29 @@ class DesktopTilingDecorViewModelTest : ShellTestCase() {
desktopTilingDecorViewModel.onUserChange()
- verify(desktopTilingDecoration, times(2)).onUserChange()
+ verify(desktopTilingDecoration, times(2)).resetTilingSession()
+ }
+
+ @Test
+ fun displayOrientationChange_tilingForDisplayShouldBeDestroyed() {
+ desktopTilingDecorViewModel.tilingTransitionHandlerByDisplayId.put(
+ 1,
+ desktopTilingDecoration,
+ )
+ desktopTilingDecorViewModel.tilingTransitionHandlerByDisplayId.put(
+ 2,
+ desktopTilingDecoration,
+ )
+
+ desktopTilingDecorViewModel.onDisplayChange(1, 1, 2, null, null)
+
+ verify(desktopTilingDecoration, times(1)).resetTilingSession()
+ verify(displayControllerMock, times(1))
+ .addDisplayChangingController(eq(desktopTilingDecorViewModel))
+
+ desktopTilingDecorViewModel.onDisplayChange(1, 1, 3, null, null)
+ // No extra calls after 180 degree change.
+ verify(desktopTilingDecoration, times(1)).resetTilingSession()
}
companion object {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt
index 0ee3f4695e85..3143946fa828 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt
@@ -16,9 +16,12 @@
package com.android.wm.shell.windowdecor.tiling
+import android.content.Context
import android.content.res.Configuration
import android.graphics.Rect
import android.testing.AndroidTestingRunner
+import android.view.Display
+import android.view.RoundedCorner
import android.view.SurfaceControl
import androidx.test.annotation.UiThreadTest
import androidx.test.filters.SmallTest
@@ -29,6 +32,7 @@ import kotlin.test.Test
import org.junit.Before
import org.junit.runner.RunWith
import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
@@ -55,10 +59,17 @@ class DesktopTilingDividerWindowManagerTest : ShellTestCase() {
private lateinit var desktopTilingWindowManager: DesktopTilingDividerWindowManager
+ private val context = mock<Context>()
+ private val display = mock<Display>()
+ private val roundedCorner = mock<RoundedCorner>()
+
@Before
fun setup() {
config = Configuration()
config.setToDefaults()
+ whenever(context.display).thenReturn(display)
+ whenever(display.getRoundedCorner(any())).thenReturn(roundedCorner)
+ whenever(roundedCorner.radius).thenReturn(CORNER_RADIUS)
desktopTilingWindowManager =
DesktopTilingDividerWindowManager(
config,
@@ -69,6 +80,7 @@ class DesktopTilingDividerWindowManagerTest : ShellTestCase() {
transitionHandlerMock,
transactionSupplierMock,
BOUNDS,
+ context,
)
}
@@ -85,7 +97,6 @@ class DesktopTilingDividerWindowManagerTest : ShellTestCase() {
// Ensure a surfaceControl transaction runs to show the divider.
verify(transactionSupplierMock, times(1)).get()
- verify(syncQueueMock, times(1)).runInSync(any())
desktopTilingWindowManager.release()
verify(transaction, times(1)).hide(any())
@@ -93,7 +104,24 @@ class DesktopTilingDividerWindowManagerTest : ShellTestCase() {
verify(transaction, times(1)).apply()
}
+ @Test
+ @UiThreadTest
+ fun testWindowManager_accountsForRoundedCornerDimensions() {
+ whenever(transactionSupplierMock.get()).thenReturn(transaction)
+ whenever(transaction.setRelativeLayer(any(), any(), any())).thenReturn(transaction)
+ whenever(transaction.setRelativeLayer(any(), any(), any())).thenReturn(transaction)
+ whenever(transaction.setPosition(any(), any(), any())).thenReturn(transaction)
+ whenever(transaction.show(any())).thenReturn(transaction)
+
+ desktopTilingWindowManager.generateViewHost(surfaceControl)
+
+ // Ensure a surfaceControl transaction runs to show the divider.
+ verify(transaction, times(1))
+ .setPosition(any(), eq(BOUNDS.left.toFloat() - CORNER_RADIUS), any())
+ }
+
companion object {
private val BOUNDS = Rect(1, 2, 3, 4)
+ private val CORNER_RADIUS = 28
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt
index 2ae2461c8f69..f371f5223419 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt
@@ -475,7 +475,7 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() {
tilingDecoration.rightTaskResizingHelper = tiledTaskHelper
tilingDecoration.desktopTilingDividerWindowManager = desktopTilingDividerWindowManager
- tilingDecoration.onUserChange()
+ tilingDecoration.resetTilingSession()
assertThat(tilingDecoration.leftTaskResizingHelper).isNull()
assertThat(tilingDecoration.rightTaskResizingHelper).isNull()
diff --git a/libs/appfunctions/api/current.txt b/libs/appfunctions/api/current.txt
index 27817e9eb984..faf84a8ab5ac 100644
--- a/libs/appfunctions/api/current.txt
+++ b/libs/appfunctions/api/current.txt
@@ -3,8 +3,9 @@ package com.google.android.appfunctions.sidecar {
public final class AppFunctionManager {
ctor public AppFunctionManager(android.content.Context);
- method public void executeAppFunction(@NonNull com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest, @NonNull java.util.concurrent.Executor, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse>);
- method public void isAppFunctionEnabled(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,java.lang.Exception>);
+ method @RequiresPermission(anyOf={android.Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED, android.Manifest.permission.EXECUTE_APP_FUNCTIONS}, conditional=true) public void executeAppFunction(@NonNull com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest, @NonNull java.util.concurrent.Executor, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse>);
+ method @RequiresPermission(anyOf={android.Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED, android.Manifest.permission.EXECUTE_APP_FUNCTIONS}, conditional=true) public void isAppFunctionEnabled(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,java.lang.Exception>);
+ method public void isAppFunctionEnabled(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,java.lang.Exception>);
method public void setAppFunctionEnabled(@NonNull String, int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,java.lang.Exception>);
field public static final int APP_FUNCTION_STATE_DEFAULT = 0; // 0x0
field public static final int APP_FUNCTION_STATE_DISABLED = 2; // 0x2
@@ -34,6 +35,7 @@ package com.google.android.appfunctions.sidecar {
}
public final class ExecuteAppFunctionResponse {
+ method public int getErrorCategory();
method @Nullable public String getErrorMessage();
method @NonNull public android.os.Bundle getExtras();
method public int getResultCode();
@@ -41,14 +43,19 @@ package com.google.android.appfunctions.sidecar {
method public boolean isSuccess();
method @NonNull public static com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse newFailure(int, @Nullable String, @Nullable android.os.Bundle);
method @NonNull public static com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse newSuccess(@NonNull android.app.appsearch.GenericDocument, @Nullable android.os.Bundle);
+ field public static final int ERROR_CATEGORY_APP = 3; // 0x3
+ field public static final int ERROR_CATEGORY_REQUEST_ERROR = 1; // 0x1
+ field public static final int ERROR_CATEGORY_SYSTEM = 2; // 0x2
+ field public static final int ERROR_CATEGORY_UNKNOWN = 0; // 0x0
field public static final String PROPERTY_RETURN_VALUE = "returnValue";
- field public static final int RESULT_APP_UNKNOWN_ERROR = 2; // 0x2
- field public static final int RESULT_CANCELLED = 6; // 0x6
- field public static final int RESULT_DENIED = 1; // 0x1
- field public static final int RESULT_DISABLED = 5; // 0x5
- field public static final int RESULT_INTERNAL_ERROR = 3; // 0x3
- field public static final int RESULT_INVALID_ARGUMENT = 4; // 0x4
+ field public static final int RESULT_APP_UNKNOWN_ERROR = 3000; // 0xbb8
+ field public static final int RESULT_CANCELLED = 2001; // 0x7d1
+ field public static final int RESULT_DENIED = 1000; // 0x3e8
+ field public static final int RESULT_DISABLED = 1002; // 0x3ea
+ field public static final int RESULT_FUNCTION_NOT_FOUND = 1003; // 0x3eb
+ field public static final int RESULT_INVALID_ARGUMENT = 1001; // 0x3e9
field public static final int RESULT_OK = 0; // 0x0
+ field public static final int RESULT_SYSTEM_ERROR = 2000; // 0x7d0
}
}
diff --git a/libs/appfunctions/java/com/google/android/appfunctions/sidecar/AppFunctionManager.java b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/AppFunctionManager.java
index 6870446fc3a0..2075104ff868 100644
--- a/libs/appfunctions/java/com/google/android/appfunctions/sidecar/AppFunctionManager.java
+++ b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/AppFunctionManager.java
@@ -16,9 +16,11 @@
package com.google.android.appfunctions.sidecar;
+import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.UserHandleAware;
import android.content.Context;
@@ -103,6 +105,12 @@ public final class AppFunctionManager {
* <p>See {@link android.app.appfunctions.AppFunctionManager#executeAppFunction} for the
* documented behaviour of this method.
*/
+ @RequiresPermission(
+ anyOf = {
+ Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED,
+ Manifest.permission.EXECUTE_APP_FUNCTIONS
+ },
+ conditional = true)
public void executeAppFunction(
@NonNull ExecuteAppFunctionRequest sidecarRequest,
@NonNull @CallbackExecutor Executor executor,
@@ -131,6 +139,12 @@ public final class AppFunctionManager {
* <p>See {@link android.app.appfunctions.AppFunctionManager#isAppFunctionEnabled} for the
* documented behaviour of this method.
*/
+ @RequiresPermission(
+ anyOf = {
+ Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED,
+ Manifest.permission.EXECUTE_APP_FUNCTIONS
+ },
+ conditional = true)
public void isAppFunctionEnabled(
@NonNull String functionIdentifier,
@NonNull String targetPackage,
@@ -140,6 +154,19 @@ public final class AppFunctionManager {
}
/**
+ * Returns a boolean through a callback, indicating whether the app function is enabled.
+ *
+ * <p>See {@link android.app.appfunctions.AppFunctionManager#isAppFunctionEnabled} for the
+ * documented behaviour of this method.
+ */
+ public void isAppFunctionEnabled(
+ @NonNull String functionIdentifier,
+ @NonNull Executor executor,
+ @NonNull OutcomeReceiver<Boolean, Exception> callback) {
+ mManager.isAppFunctionEnabled(functionIdentifier, executor, callback);
+ }
+
+ /**
* Sets the enabled state of the app function owned by the calling package.
*
* <p>See {@link android.app.appfunctions.AppFunctionManager#setAppFunctionEnabled} for the
diff --git a/libs/appfunctions/java/com/google/android/appfunctions/sidecar/ExecuteAppFunctionResponse.java b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/ExecuteAppFunctionResponse.java
index d5dfaeb77140..4e88fb025a9d 100644
--- a/libs/appfunctions/java/com/google/android/appfunctions/sidecar/ExecuteAppFunctionResponse.java
+++ b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/ExecuteAppFunctionResponse.java
@@ -50,38 +50,102 @@ public final class ExecuteAppFunctionResponse {
*/
public static final String PROPERTY_RETURN_VALUE = "returnValue";
- /** The call was successful. */
+ /**
+ * The call was successful.
+ *
+ * <p>This result code does not belong in an error category.
+ */
public static final int RESULT_OK = 0;
- /** The caller does not have the permission to execute an app function. */
- public static final int RESULT_DENIED = 1;
+ /**
+ * The caller does not have the permission to execute an app function.
+ *
+ * <p>This error is in the {@link #ERROR_CATEGORY_REQUEST_ERROR} category.
+ */
+ public static final int RESULT_DENIED = 1000;
+
+ /**
+ * The caller supplied invalid arguments to the execution request.
+ *
+ * <p>This error may be considered similar to {@link IllegalArgumentException}.
+ *
+ * <p>This error is in the {@link #ERROR_CATEGORY_REQUEST_ERROR} category.
+ */
+ public static final int RESULT_INVALID_ARGUMENT = 1001;
+
+ /**
+ * The caller tried to execute a disabled app function.
+ *
+ * <p>This error is in the {@link #ERROR_CATEGORY_REQUEST_ERROR} category.
+ */
+ public static final int RESULT_DISABLED = 1002;
+
+ /**
+ * The caller tried to execute a function that does not exist.
+ *
+ * <p>This error is in the {@link #ERROR_CATEGORY_REQUEST_ERROR} category.
+ */
+ public static final int RESULT_FUNCTION_NOT_FOUND = 1003;
+
+ /**
+ * An internal unexpected error coming from the system.
+ *
+ * <p>This error is in the {@link #ERROR_CATEGORY_SYSTEM} category.
+ */
+ public static final int RESULT_SYSTEM_ERROR = 2000;
+
+ /**
+ * The operation was cancelled. Use this error code to report that a cancellation is done after
+ * receiving a cancellation signal.
+ *
+ * <p>This error is in the {@link #ERROR_CATEGORY_SYSTEM} category.
+ */
+ public static final int RESULT_CANCELLED = 2001;
/**
* An unknown error occurred while processing the call in the AppFunctionService.
*
* <p>This error is thrown when the service is connected in the remote application but an
* unexpected error is thrown from the bound application.
+ *
+ * <p>This error is in the {@link #ERROR_CATEGORY_APP} category.
*/
- public static final int RESULT_APP_UNKNOWN_ERROR = 2;
+ public static final int RESULT_APP_UNKNOWN_ERROR = 3000;
- /** An internal unexpected error coming from the system. */
- public static final int RESULT_INTERNAL_ERROR = 3;
+ /**
+ * The error category is unknown.
+ *
+ * <p>This is the default value for {@link #getErrorCategory}.
+ */
+ public static final int ERROR_CATEGORY_UNKNOWN = 0;
/**
- * The caller supplied invalid arguments to the call.
+ * The error is caused by the app requesting a function execution.
*
- * <p>This error may be considered similar to {@link IllegalArgumentException}.
+ * <p>For example, the caller provided invalid parameters in the execution request e.g. an
+ * invalid function ID.
+ *
+ * <p>Errors in the category fall in the range 1000-1999 inclusive.
*/
- public static final int RESULT_INVALID_ARGUMENT = 4;
+ public static final int ERROR_CATEGORY_REQUEST_ERROR = 1;
- /** The caller tried to execute a disabled app function. */
- public static final int RESULT_DISABLED = 5;
+ /**
+ * The error is caused by an issue in the system.
+ *
+ * <p>For example, the AppFunctionService implementation is not found by the system.
+ *
+ * <p>Errors in the category fall in the range 2000-2999 inclusive.
+ */
+ public static final int ERROR_CATEGORY_SYSTEM = 2;
/**
- * The operation was cancelled. Use this error code to report that a cancellation is done after
- * receiving a cancellation signal.
+ * The error is caused by the app providing the function.
+ *
+ * <p>For example, the app crashed when the system is executing the request.
+ *
+ * <p>Errors in the category fall in the range 3000-3999 inclusive.
*/
- public static final int RESULT_CANCELLED = 6;
+ public static final int ERROR_CATEGORY_APP = 3;
/** The result code of the app function execution. */
@ResultCode private final int mResultCode;
@@ -171,6 +235,36 @@ public final class ExecuteAppFunctionResponse {
}
/**
+ * Returns the error category of the {@link ExecuteAppFunctionResponse}.
+ *
+ * <p>This method categorizes errors based on their underlying cause, allowing developers to
+ * implement targeted error handling and provide more informative error messages to users. It
+ * maps ranges of result codes to specific error categories.
+ *
+ * <p>When constructing a {@link #newFailure} response, use the appropriate result code value to
+ * ensure correct categorization of the failed response.
+ *
+ * <p>This method returns {@code ERROR_CATEGORY_UNKNOWN} if the result code does not belong to
+ * any error category, for example, in the case of a successful result with {@link #RESULT_OK}.
+ *
+ * <p>See {@link ErrorCategory} for a complete list of error categories and their corresponding
+ * result code ranges.
+ */
+ @ErrorCategory
+ public int getErrorCategory() {
+ if (mResultCode >= 1000 && mResultCode < 2000) {
+ return ERROR_CATEGORY_REQUEST_ERROR;
+ }
+ if (mResultCode >= 2000 && mResultCode < 3000) {
+ return ERROR_CATEGORY_SYSTEM;
+ }
+ if (mResultCode >= 3000 && mResultCode < 4000) {
+ return ERROR_CATEGORY_APP;
+ }
+ return ERROR_CATEGORY_UNKNOWN;
+ }
+
+ /**
* Returns a generic document containing the return value of the executed function.
*
* <p>The {@link #PROPERTY_RETURN_VALUE} key can be used to obtain the return value.
@@ -238,11 +332,28 @@ public final class ExecuteAppFunctionResponse {
RESULT_OK,
RESULT_DENIED,
RESULT_APP_UNKNOWN_ERROR,
- RESULT_INTERNAL_ERROR,
+ RESULT_SYSTEM_ERROR,
+ RESULT_FUNCTION_NOT_FOUND,
RESULT_INVALID_ARGUMENT,
RESULT_DISABLED,
RESULT_CANCELLED
})
@Retention(RetentionPolicy.SOURCE)
public @interface ResultCode {}
+
+ /**
+ * Error categories.
+ *
+ * @hide
+ */
+ @IntDef(
+ prefix = {"ERROR_CATEGORY_"},
+ value = {
+ ERROR_CATEGORY_UNKNOWN,
+ ERROR_CATEGORY_REQUEST_ERROR,
+ ERROR_CATEGORY_APP,
+ ERROR_CATEGORY_SYSTEM
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ErrorCategory {}
}
diff --git a/libs/appfunctions/tests/src/com/google/android/appfunctions/sidecar/tests/SidecarConverterTest.kt b/libs/appfunctions/tests/src/com/google/android/appfunctions/sidecar/tests/SidecarConverterTest.kt
index 1f9fddd3c1ec..264f84209caf 100644
--- a/libs/appfunctions/tests/src/com/google/android/appfunctions/sidecar/tests/SidecarConverterTest.kt
+++ b/libs/appfunctions/tests/src/com/google/android/appfunctions/sidecar/tests/SidecarConverterTest.kt
@@ -105,7 +105,7 @@ class SidecarConverterTest {
val emptyGd = GenericDocument.Builder<GenericDocument.Builder<*>>("", "", "").build()
val platformResponse =
ExecuteAppFunctionResponse.newFailure(
- ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR,
+ ExecuteAppFunctionResponse.RESULT_SYSTEM_ERROR,
null,
null
)
@@ -119,7 +119,7 @@ class SidecarConverterTest {
assertThat(sidecarResponse.resultDocument.id).isEqualTo(emptyGd.id)
assertThat(sidecarResponse.resultDocument.schemaType).isEqualTo(emptyGd.schemaType)
assertThat(sidecarResponse.resultCode)
- .isEqualTo(ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR)
+ .isEqualTo(ExecuteAppFunctionResponse.RESULT_SYSTEM_ERROR)
assertThat(sidecarResponse.errorMessage).isNull()
}
@@ -152,7 +152,7 @@ class SidecarConverterTest {
val emptyGd = GenericDocument.Builder<GenericDocument.Builder<*>>("", "", "").build()
val sidecarResponse =
com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse.newFailure(
- ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR,
+ ExecuteAppFunctionResponse.RESULT_SYSTEM_ERROR,
null,
null
)
@@ -166,7 +166,7 @@ class SidecarConverterTest {
assertThat(platformResponse.resultDocument.id).isEqualTo(emptyGd.id)
assertThat(platformResponse.resultDocument.schemaType).isEqualTo(emptyGd.schemaType)
assertThat(platformResponse.resultCode)
- .isEqualTo(ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR)
+ .isEqualTo(ExecuteAppFunctionResponse.RESULT_SYSTEM_ERROR)
assertThat(platformResponse.errorMessage).isNull()
}
}
diff --git a/libs/hwui/aconfig/hwui_flags.aconfig b/libs/hwui/aconfig/hwui_flags.aconfig
index f2559677c325..5ad788c67816 100644
--- a/libs/hwui/aconfig/hwui_flags.aconfig
+++ b/libs/hwui/aconfig/hwui_flags.aconfig
@@ -146,3 +146,11 @@ flag {
description: "Whether to have more information in ashmem filenames for bitmaps"
bug: "369619160"
}
+
+flag {
+ name: "animated_image_drawable_filter_bitmap"
+ is_exported: true
+ namespace: "core_graphics"
+ description: "API's that enable animated image drawables to use nearest sampling when scaling."
+ bug: "370523334"
+}
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp
index 69613c7d17cb..5e379aad9326 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.cpp
+++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp
@@ -347,4 +347,26 @@ int AnimatedImageDrawable::currentFrameDuration() {
return adjustFrameDuration(mSkAnimatedImage->currentFrameDuration());
}
+bool AnimatedImageDrawable::getFilterBitmap() const {
+ const SkFilterMode kFilterBitmap = mSkAnimatedImage->getFilterMode();
+ if (kFilterBitmap == SkFilterMode::kLinear) {
+ return true;
+ }
+ return false;
+}
+
+bool AnimatedImageDrawable::setFilterBitmap(bool filterBitmap) {
+ if (filterBitmap) {
+ if (mSkAnimatedImage->getFilterMode() == SkFilterMode::kLinear) {
+ return false;
+ }
+ mSkAnimatedImage->setFilterMode(SkFilterMode::kLinear);
+ } else {
+ if (mSkAnimatedImage->getFilterMode() == SkFilterMode::kNearest) {
+ return false;
+ }
+ mSkAnimatedImage->setFilterMode(SkFilterMode::kNearest);
+ }
+ return true;
+}
} // namespace android
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.h b/libs/hwui/hwui/AnimatedImageDrawable.h
index 1e965abc82b5..22123249b7d6 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.h
+++ b/libs/hwui/hwui/AnimatedImageDrawable.h
@@ -87,6 +87,11 @@ public:
bool isRunning();
int getRepetitionCount() const { return mSkAnimatedImage->getRepetitionCount(); }
void setRepetitionCount(int count) { mSkAnimatedImage->setRepetitionCount(count); }
+ // Returns true if the filter mode is set to linear sampling; false if it is
+ // set to nearest neighbor sampling.
+ bool getFilterBitmap() const;
+ // Returns true if the filter mode was changed; false otherwise.
+ bool setFilterBitmap(bool filterBitmap);
void setOnAnimationEndListener(std::unique_ptr<OnAnimationEndListener> listener) {
mEndListener = std::move(listener);
diff --git a/libs/hwui/jni/AnimatedImageDrawable.cpp b/libs/hwui/jni/AnimatedImageDrawable.cpp
index b01e38d014a9..2c8530d4daeb 100644
--- a/libs/hwui/jni/AnimatedImageDrawable.cpp
+++ b/libs/hwui/jni/AnimatedImageDrawable.cpp
@@ -276,6 +276,18 @@ static void AnimatedImageDrawable_nSetBounds(JNIEnv* env, jobject /*clazz*/, jlo
drawable->setStagingBounds(rect);
}
+static jboolean AnimatedImageDrawable_nSetFilterBitmap(JNIEnv* env, jobject /*clazz*/,
+ jlong nativePtr, jboolean filterBitmap) {
+ auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
+ return drawable->setFilterBitmap(filterBitmap);
+}
+
+static jboolean AnimatedImageDrawable_nGetFilterBitmap(JNIEnv* env, jobject /*clazz*/,
+ jlong nativePtr) {
+ auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
+ return drawable->getFilterBitmap();
+}
+
static const JNINativeMethod gAnimatedImageDrawableMethods[] = {
{"nCreate", "(JLandroid/graphics/ImageDecoder;IIJZLandroid/graphics/Rect;)J",
(void*)AnimatedImageDrawable_nCreate},
@@ -294,6 +306,8 @@ static const JNINativeMethod gAnimatedImageDrawableMethods[] = {
{"nNativeByteSize", "(J)J", (void*)AnimatedImageDrawable_nNativeByteSize},
{"nSetMirrored", "(JZ)V", (void*)AnimatedImageDrawable_nSetMirrored},
{"nSetBounds", "(JLandroid/graphics/Rect;)V", (void*)AnimatedImageDrawable_nSetBounds},
+ {"nSetFilterBitmap", "(JZ)Z", (void*)AnimatedImageDrawable_nSetFilterBitmap},
+ {"nGetFilterBitmap", "(J)Z", (void*)AnimatedImageDrawable_nGetFilterBitmap},
};
int register_android_graphics_drawable_AnimatedImageDrawable(JNIEnv* env) {
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 5a8eb3ab17b8..1db719828c76 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -16,15 +16,11 @@
package android.media;
-import static android.media.audio.Flags.FLAG_SPEAKER_CLEANUP_USAGE;
-
-import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-// TODO switch from HIDL imports to AIDL
import android.audio.policy.configuration.V7_0.AudioUsage;
import android.compat.annotation.UnsupportedAppUsage;
import android.media.audiopolicy.AudioProductStrategy;
@@ -251,16 +247,6 @@ public final class AudioAttributes implements Parcelable {
public static final int USAGE_ANNOUNCEMENT = SYSTEM_USAGE_OFFSET + 3;
/**
- * @hide
- * Usage value to use when a system application plays a signal intended to clean up the
- * speaker transducers and free them of deposits of dust or water.
- */
- @FlaggedApi(FLAG_SPEAKER_CLEANUP_USAGE)
- @SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
- public static final int USAGE_SPEAKER_CLEANUP = SYSTEM_USAGE_OFFSET + 4;
-
- /**
* IMPORTANT: when adding new usage types, add them to SDK_USAGES and update SUPPRESSIBLE_USAGES
* if applicable, as well as audioattributes.proto.
* Also consider adding them to <aaudio/AAudio.h> for the NDK.
@@ -1216,7 +1202,6 @@ public final class AudioAttributes implements Parcelable {
break;
case AudioSystem.STREAM_BLUETOOTH_SCO:
mContentType = CONTENT_TYPE_SPEECH;
- mFlags |= FLAG_SCO;
break;
case AudioSystem.STREAM_DTMF:
mContentType = CONTENT_TYPE_SONIFICATION;
@@ -1536,8 +1521,6 @@ public final class AudioAttributes implements Parcelable {
return "USAGE_VEHICLE_STATUS";
case USAGE_ANNOUNCEMENT:
return "USAGE_ANNOUNCEMENT";
- case USAGE_SPEAKER_CLEANUP:
- return "USAGE_SPEAKER_CLEANUP";
default:
return "unknown usage " + usage;
}
@@ -1678,8 +1661,12 @@ public final class AudioAttributes implements Parcelable {
}
/**
- * Returns whether the given usage can only be used by system-privileged components
- * @param usage one of {@link AttributeSystemUsage}.
+ * @param usage one of {@link AttributeSystemUsage},
+ * {@link AttributeSystemUsage#USAGE_CALL_ASSISTANT},
+ * {@link AttributeSystemUsage#USAGE_EMERGENCY},
+ * {@link AttributeSystemUsage#USAGE_SAFETY},
+ * {@link AttributeSystemUsage#USAGE_VEHICLE_STATUS},
+ * {@link AttributeSystemUsage#USAGE_ANNOUNCEMENT}
* @return boolean indicating if the usage is a system usage or not
* @hide
*/
@@ -1689,8 +1676,7 @@ public final class AudioAttributes implements Parcelable {
|| usage == USAGE_EMERGENCY
|| usage == USAGE_SAFETY
|| usage == USAGE_VEHICLE_STATUS
- || usage == USAGE_ANNOUNCEMENT
- || usage == USAGE_SPEAKER_CLEANUP);
+ || usage == USAGE_ANNOUNCEMENT);
}
/**
@@ -1763,8 +1749,7 @@ public final class AudioAttributes implements Parcelable {
AudioSystem.STREAM_SYSTEM : AudioSystem.STREAM_SYSTEM_ENFORCED;
}
if ((aa.getAllFlags() & FLAG_SCO) == FLAG_SCO) {
- return fromGetVolumeControlStream ?
- AudioSystem.STREAM_VOICE_CALL : AudioSystem.STREAM_BLUETOOTH_SCO;
+ return AudioSystem.STREAM_VOICE_CALL;
}
if ((aa.getAllFlags() & FLAG_BEACON) == FLAG_BEACON) {
return fromGetVolumeControlStream ?
@@ -1805,7 +1790,6 @@ public final class AudioAttributes implements Parcelable {
case USAGE_SAFETY:
case USAGE_VEHICLE_STATUS:
case USAGE_ANNOUNCEMENT:
- case USAGE_SPEAKER_CLEANUP:
case USAGE_UNKNOWN:
return AudioSystem.STREAM_MUSIC;
default:
@@ -1845,8 +1829,7 @@ public final class AudioAttributes implements Parcelable {
USAGE_EMERGENCY,
USAGE_SAFETY,
USAGE_VEHICLE_STATUS,
- USAGE_ANNOUNCEMENT,
- USAGE_SPEAKER_CLEANUP
+ USAGE_ANNOUNCEMENT
})
@Retention(RetentionPolicy.SOURCE)
public @interface AttributeSystemUsage {}
@@ -1896,7 +1879,6 @@ public final class AudioAttributes implements Parcelable {
USAGE_SAFETY,
USAGE_VEHICLE_STATUS,
USAGE_ANNOUNCEMENT,
- USAGE_SPEAKER_CLEANUP,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AttributeUsage {}
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index 39b29d0156d2..2da8eecedc4d 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -16,11 +16,15 @@
package android.media;
+import static android.media.audio.Flags.FLAG_ENABLE_MULTICHANNEL_GROUP_DEVICE;
+
import android.Manifest;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.TestApi;
+import android.media.audio.Flags;
import android.util.SparseIntArray;
import com.android.internal.annotations.VisibleForTesting;
@@ -192,6 +196,15 @@ public final class AudioDeviceInfo {
*/
public static final int TYPE_DOCK_ANALOG = 31;
+ /**
+ * A device type describing a speaker group that supports multichannel contents. The speakers in
+ * the group are connected together using local network based protocols. The speaker group
+ * requires additional input of the physical positions of each individual speaker to provide a
+ * better experience on multichannel contents.
+ */
+ @FlaggedApi(FLAG_ENABLE_MULTICHANNEL_GROUP_DEVICE)
+ public static final int TYPE_MULTICHANNEL_GROUP = 32;
+
/** @hide */
@IntDef(flag = false, prefix = "TYPE", value = {
TYPE_BUILTIN_EARPIECE,
@@ -224,7 +237,8 @@ public final class AudioDeviceInfo {
TYPE_BLE_SPEAKER,
TYPE_ECHO_REFERENCE,
TYPE_BLE_BROADCAST,
- TYPE_DOCK_ANALOG}
+ TYPE_DOCK_ANALOG,
+ TYPE_MULTICHANNEL_GROUP}
)
@Retention(RetentionPolicy.SOURCE)
public @interface AudioDeviceType {}
@@ -285,7 +299,8 @@ public final class AudioDeviceInfo {
TYPE_BLE_HEADSET,
TYPE_BLE_SPEAKER,
TYPE_BLE_BROADCAST,
- TYPE_DOCK_ANALOG}
+ TYPE_DOCK_ANALOG,
+ TYPE_MULTICHANNEL_GROUP}
)
@Retention(RetentionPolicy.SOURCE)
public @interface AudioDeviceTypeOut {}
@@ -321,7 +336,13 @@ public final class AudioDeviceInfo {
case TYPE_BLE_BROADCAST:
case TYPE_DOCK_ANALOG:
return true;
+
default:
+ if (Flags.enableMultichannelGroupDevice()) {
+ if (type == TYPE_MULTICHANNEL_GROUP) {
+ return true;
+ }
+ }
return false;
}
}
@@ -665,6 +686,10 @@ public final class AudioDeviceInfo {
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLE_HEADSET, TYPE_BLE_HEADSET);
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLE_SPEAKER, TYPE_BLE_SPEAKER);
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLE_BROADCAST, TYPE_BLE_BROADCAST);
+ if (Flags.enableMultichannelGroupDevice()) {
+ INT_TO_EXT_DEVICE_MAPPING.put(
+ AudioSystem.DEVICE_OUT_MULTICHANNEL_GROUP, TYPE_MULTICHANNEL_GROUP);
+ }
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUILTIN_MIC, TYPE_BUILTIN_MIC);
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET, TYPE_BLUETOOTH_SCO);
@@ -721,6 +746,10 @@ public final class AudioDeviceInfo {
EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_HEADSET, AudioSystem.DEVICE_OUT_BLE_HEADSET);
EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_SPEAKER, AudioSystem.DEVICE_OUT_BLE_SPEAKER);
EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_BROADCAST, AudioSystem.DEVICE_OUT_BLE_BROADCAST);
+ if (Flags.enableMultichannelGroupDevice()) {
+ EXT_TO_INT_DEVICE_MAPPING.put(
+ TYPE_MULTICHANNEL_GROUP, AudioSystem.DEVICE_OUT_MULTICHANNEL_GROUP);
+ }
// privileges mapping to input device
EXT_TO_INT_INPUT_DEVICE_MAPPING = new SparseIntArray();
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 8250a536552e..dfe291605522 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -6156,6 +6156,11 @@ public class AudioManager {
*/
public static final int DEVICE_OUT_BLE_BROADCAST = AudioSystem.DEVICE_OUT_BLE_BROADCAST;
/** @hide
+ * The audio output device code for a wireless speaker group supporting multichannel content.
+ */
+ public static final int DEVICE_OUT_MULTICHANNEL_GROUP =
+ AudioSystem.DEVICE_OUT_MULTICHANNEL_GROUP;
+ /** @hide
* This is not used as a returned value from {@link #getDevicesForStream}, but could be
* used in the future in a set method to select whatever default device is chosen by the
* platform-specific implementation.
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index bf09cb07a8ed..0ab94f567506 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1066,6 +1066,8 @@ public class AudioSystem
/** @hide */
public static final int DEVICE_OUT_IP = 0x800000;
/** @hide */
+ public static final int DEVICE_OUT_MULTICHANNEL_GROUP = 0x800001;
+ /** @hide */
public static final int DEVICE_OUT_BUS = 0x1000000;
/** @hide */
public static final int DEVICE_OUT_PROXY = 0x2000000;
@@ -1134,6 +1136,7 @@ public class AudioSystem
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_AUX_LINE);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_SPEAKER_SAFE);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_IP);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_MULTICHANNEL_GROUP);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BUS);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_PROXY);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_USB_HEADSET);
@@ -1422,6 +1425,8 @@ public class AudioSystem
/** @hide */ public static final String DEVICE_OUT_AUX_LINE_NAME = "aux_line";
/** @hide */ public static final String DEVICE_OUT_SPEAKER_SAFE_NAME = "speaker_safe";
/** @hide */ public static final String DEVICE_OUT_IP_NAME = "ip";
+ /** @hide */
+ public static final String DEVICE_OUT_MULTICHANNEL_GROUP_NAME = "multichannel_group";
/** @hide */ public static final String DEVICE_OUT_BUS_NAME = "bus";
/** @hide */ public static final String DEVICE_OUT_PROXY_NAME = "proxy";
/** @hide */ public static final String DEVICE_OUT_USB_HEADSET_NAME = "usb_headset";
@@ -1515,6 +1520,8 @@ public class AudioSystem
return DEVICE_OUT_SPEAKER_SAFE_NAME;
case DEVICE_OUT_IP:
return DEVICE_OUT_IP_NAME;
+ case DEVICE_OUT_MULTICHANNEL_GROUP:
+ return DEVICE_OUT_MULTICHANNEL_GROUP_NAME;
case DEVICE_OUT_BUS:
return DEVICE_OUT_BUS_NAME;
case DEVICE_OUT_PROXY:
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 3a19f466f7c1..96edd63a9b12 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -23,6 +23,7 @@ import static android.media.codec.Flags.FLAG_HLG_EDITING;
import static android.media.codec.Flags.FLAG_IN_PROCESS_SW_AUDIO_CODEC;
import static android.media.codec.Flags.FLAG_NULL_OUTPUT_SURFACE;
import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST;
+import static android.media.codec.Flags.FLAG_APV_SUPPORT;
import static android.media.MediaCodec.GetFlag;
import android.annotation.FlaggedApi;
@@ -4496,6 +4497,265 @@ public final class MediaCodecInfo {
@SuppressLint("AllUpper")
public static final int AC4Level4 = 0x10;
+ // Profiles and levels/bands for APV Codec, corresponding to the definitions in
+ // "Advanced Professional Video", 10.1.3 Profiles, 10.1.4 Levels and Bands
+ // found at https://www.ietf.org/archive/id/draft-lim-apv-02.html
+
+ /**
+ * APV codec profile 422-10 as per IETF lim-apv-02, 10.1.3.1.1
+ */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVProfile422_10 = 0x01;
+
+ /**
+ * APV codec profile 422-10 as per IETF lim-apv-02, 10.1.3.1.1
+ * with HDR10.
+ */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVProfile422_10HDR10 = 0x1000;
+
+ /**
+ * APV codec profile 422-10 as per IETF lim-apv-02, 10.1.3.1.1
+ * with HDR10Plus.
+ */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVProfile422_10HDR10Plus = 0x2000;
+
+ // For APV Levels, the numerical values are constructed as follows:
+ // ((0x100 << (level_num - 1)) | (1 << band))
+ // where:
+ // - "level_num" is the APV Level numbered consecutively
+ // (i.e., Level 1 == 1, Level 1.1 == 2, etc.)
+ // - "band" is the APV Band
+
+ /** APV Codec Level 1, Band 0 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel1Band0 = 0x101;
+ /** APV Codec Level 1, Band 1 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel1Band1 = 0x102;
+ /** APV Codec Level 1, Band 2 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel1Band2 = 0x104;
+ /** APV Codec Level 1, Band 3 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel1Band3 = 0x108;
+ /** APV Codec Level 1.1, Band 0 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel11Band0 = 0x201;
+ /** APV Codec Level 1.1, Band 1 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel11Band1 = 0x202;
+ /** APV Codec Level 1.1, Band 2 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel11Band2 = 0x204;
+ /** APV Codec Level 1.1, Band 3 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel11Band3 = 0x208;
+ /** APV Codec Level 2, Band 0 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel2Band0 = 0x401;
+ /** APV Codec Level 2, Band 1 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel2Band1 = 0x402;
+ /** APV Codec Level 2, Band 2 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel2Band2 = 0x404;
+ /** APV Codec Level 2, Band 3 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel2Band3 = 0x408;
+ /** APV Codec Level 2.1, Band 0 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel21Band0 = 0x801;
+ /** APV Codec Level 2.1, Band 1 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel21Band1 = 0x802;
+ /** APV Codec Level 2.1, Band 2 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel21Band2 = 0x804;
+ /** APV Codec Level 2.1, Band 3 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel21Band3 = 0x808;
+ /** APV Codec Level 3, Band 0 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel3Band0 = 0x1001;
+ /** APV Codec Level 3, Band 1 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel3Band1 = 0x1002;
+ /** APV Codec Level 3, Band 2 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel3Band2 = 0x1004;
+ /** APV Codec Level 3, Band 3 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel3Band3 = 0x1008;
+ /** APV Codec Level 3.1, Band 0 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel31Band0 = 0x2001;
+ /** APV Codec Level 3.1, Band 1 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel31Band1 = 0x2002;
+ /** APV Codec Level 3.1, Band 2 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel31Band2 = 0x2004;
+ /** APV Codec Level 3.1, Band 3 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel31Band3 = 0x2008;
+ /** APV Codec Level 4, Band 0 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel4Band0 = 0x4001;
+ /** APV Codec Level 4, Band 1 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel4Band1 = 0x4002;
+ /** APV Codec Level 4, Band 2 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel4Band2 = 0x4004;
+ /** APV Codec Level 4, Band 3 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel4Band3 = 0x4008;
+ /** APV Codec Level 4.1, Band 0 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel41Band0 = 0x8001;
+ /** APV Codec Level 4.1, Band 1 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel41Band1 = 0x8002;
+ /** APV Codec Level 4.1, Band 2 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel41Band2 = 0x8004;
+ /** APV Codec Level 4.1, Band 3 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel41Band3 = 0x8008;
+ /** APV Codec Level 5, Band 0 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel5Band0 = 0x10001;
+ /** APV Codec Level 5, Band 1 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel5Band1 = 0x10002;
+ /** APV Codec Level 5, Band 2 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel5Band2 = 0x10004;
+ /** APV Codec Level 5, Band 3 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel5Band3 = 0x10008;
+ /** APV Codec Level 5.1, Band 0 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel51Band0 = 0x20001;
+ /** APV Codec Level 5.1, Band 1 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel51Band1 = 0x20002;
+ /** APV Codec Level 5.1, Band 2 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel51Band2 = 0x20004;
+ /** APV Codec Level 5.1, Band 3 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel51Band3 = 0x20008;
+ /** APV Codec Level 6, Band 0 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel6Band0 = 0x40001;
+ /** APV Codec Level 6, Band 1 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel6Band1 = 0x40002;
+ /** APV Codec Level 6, Band 2 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel6Band2 = 0x40004;
+ /** APV Codec Level 6, Band 3 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel6Band3 = 0x40008;
+ /** APV Codec Level 6.1, Band 0 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel61Band0 = 0x80001;
+ /** APV Codec Level 6.1, Band 1 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel61Band1 = 0x80002;
+ /** APV Codec Level 6.1, Band 2 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel61Band2 = 0x80004;
+ /** APV Codec Level 6.1, Band 3 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel61Band3 = 0x80008;
+ /** APV Codec Level 7, Band 0 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel7Band0 = 0x100001;
+ /** APV Codec Level 7, Band 1 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel7Band1 = 0x100002;
+ /** APV Codec Level 7, Band 2 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel7Band2 = 0x100004;
+ /** APV Codec Level 7, Band 3 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel7Band3 = 0x100008;
+ /** APV Codec Level 7.1, Band 0 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel71Band0 = 0x200001;
+ /** APV Codec Level 7.1, Band 1 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel71Band1 = 0x200002;
+ /** APV Codec Level 7.1, Band 2 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel71Band2 = 0x200004;
+ /** APV Codec Level 7.1, Band 3 as per IETF lim-apv-02, 10.1.4 */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final int APVLevel71Band3 = 0x200008;
+
/**
* The profile of the media content. Depending on the type of media this can be
* one of the profile values defined in this class.
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index cd0654ceb348..b08a86ee8f46 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -18,6 +18,7 @@ package android.media;
import static android.media.codec.Flags.FLAG_IN_PROCESS_SW_AUDIO_CODEC;
import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST;
+import static android.media.codec.Flags.FLAG_APV_SUPPORT;
import static com.android.media.codec.flags.Flags.FLAG_CODEC_IMPORTANCE;
import static com.android.media.codec.flags.Flags.FLAG_LARGE_AUDIO_FRAME;
@@ -157,6 +158,8 @@ import java.util.stream.Collectors;
public final class MediaFormat {
public static final String MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
public static final String MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
+ @FlaggedApi(FLAG_APV_SUPPORT)
+ public static final String MIMETYPE_VIDEO_APV = "video/apv";
public static final String MIMETYPE_VIDEO_AV1 = "video/av01";
public static final String MIMETYPE_VIDEO_AVC = "video/avc";
public static final String MIMETYPE_VIDEO_HEVC = "video/hevc";
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index bdfa63010adc..2d17bf500f12 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -387,13 +387,13 @@ public class MediaRecorder implements AudioRouting,
/**
* Audio source for capturing broadcast radio tuner output.
* Capturing the radio tuner output requires the
- * {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT} permission.
+ * {@link android.Manifest.permission#CAPTURE_TUNER_AUDIO_INPUT} permission.
* This permission is reserved for use by system components and is not available to
* third-party applications.
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT)
+ @RequiresPermission(android.Manifest.permission.CAPTURE_TUNER_AUDIO_INPUT)
public static final int RADIO_TUNER = 1998;
/**
diff --git a/nfc/java/android/nfc/flags.aconfig b/nfc/java/android/nfc/flags.aconfig
index 6a7e6939e773..34f020012d3c 100644
--- a/nfc/java/android/nfc/flags.aconfig
+++ b/nfc/java/android/nfc/flags.aconfig
@@ -165,3 +165,11 @@ flag {
description: "Enabling security log for nfc state change"
bug: "319934052"
}
+
+flag {
+ name: "nfc_associated_role_services"
+ is_exported: true
+ namespace: "nfc"
+ description: "Share wallet role routing priority with associated services"
+ bug: "366243361"
+}
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index b76b028ac4b9..4d334660895e 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -82,7 +82,7 @@
<string name="speed_label_very_fast" msgid="8215718029533182439">"Veoma brzo"</string>
<string name="wifi_passpoint_expired" msgid="6540867261754427561">"Isteklo"</string>
<string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
- <string name="bluetooth_disconnected" msgid="7739366554710388701">"Isključen"</string>
+ <string name="bluetooth_disconnected" msgid="7739366554710388701">"Nije povezano"</string>
<string name="bluetooth_disconnecting" msgid="7638892134401574338">"Prekidanje veze…"</string>
<string name="bluetooth_connecting" msgid="5871702668260192755">"Povezivanje…"</string>
<string name="bluetooth_connected" msgid="8065345572198502293">"Povezano<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index 038800cf4bfa..00ea04d68c16 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -29,7 +29,7 @@
<item msgid="4613015005934755724">"Terhubung"</item>
<item msgid="3763530049995655072">"Ditangguhkan"</item>
<item msgid="7852381437933824454">"Memutus sambungan..."</item>
- <item msgid="5046795712175415059">"Sambungan terputus"</item>
+ <item msgid="5046795712175415059">"Tidak terhubung"</item>
<item msgid="2473654476624070462">"Gagal"</item>
<item msgid="9146847076036105115">"Diblokir"</item>
<item msgid="4543924085816294893">"Menghindari sambungan buruk untuk sementara"</item>
@@ -43,7 +43,7 @@
<item msgid="1043944043827424501">"Terhubung ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
<item msgid="7445993821842009653">"Ditangguhkan"</item>
<item msgid="1175040558087735707">"Diputus dari <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
- <item msgid="699832486578171722">"Sambungan terputus"</item>
+ <item msgid="699832486578171722">"Tidak terhubung"</item>
<item msgid="522383512264986901">"Gagal"</item>
<item msgid="3602596701217484364">"Diblokir"</item>
<item msgid="1999413958589971747">"Menghindari sambungan buruk untuk sementara"</item>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 3b265f8e9d38..bfd8f397be60 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -50,7 +50,7 @@
<string name="wifi_security_owe" msgid="3343421403561657809">"Enhanced Open"</string>
<string name="wifi_security_eap_suiteb" msgid="415842785991698142">"WPA3-Enterprise 192-bit"</string>
<string name="wifi_remembered" msgid="3266709779723179188">"Disimpan"</string>
- <string name="wifi_disconnected" msgid="7054450256284661757">"Terputus"</string>
+ <string name="wifi_disconnected" msgid="7054450256284661757">"Tidak terhubung"</string>
<string name="wifi_disabled_generic" msgid="2651916945380294607">"Nonaktif"</string>
<string name="wifi_disabled_network_failure" msgid="2660396183242399585">"Kegagalan Konfigurasi IP"</string>
<string name="wifi_disabled_password_failure" msgid="6892387079613226738">"Masalah autentikasi"</string>
@@ -82,7 +82,7 @@
<string name="speed_label_very_fast" msgid="8215718029533182439">"Sangat Cepat"</string>
<string name="wifi_passpoint_expired" msgid="6540867261754427561">"Sudah tidak berlaku"</string>
<string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
- <string name="bluetooth_disconnected" msgid="7739366554710388701">"Sambungan terputus"</string>
+ <string name="bluetooth_disconnected" msgid="7739366554710388701">"Tidak terhubung"</string>
<string name="bluetooth_disconnecting" msgid="7638892134401574338">"Memutus sambungan..."</string>
<string name="bluetooth_connecting" msgid="5871702668260192755">"Menghubungkan…"</string>
<string name="bluetooth_connected" msgid="8065345572198502293">"Terhubung<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 2fb036f8356c..785bf43bb4d1 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -258,7 +258,7 @@
<string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR кодунун сканерин колдонуп, жаңы түзмөктөрдү жупташтырыңыз"</string>
<string name="adb_pair_method_code_title" msgid="1122590300445142904">"Түзмөктү атайын код аркылуу жупташтыруу"</string>
<string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Жаңы түзмөктөрдү алты сандан турган код аркылуу жупташтырасыз"</string>
- <string name="adb_paired_devices_title" msgid="5268997341526217362">"Жупташтырылган түзмөктөр"</string>
+ <string name="adb_paired_devices_title" msgid="5268997341526217362">"Байланышкан түзмөктөр"</string>
<string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Учурда туташып турган түзмөктөр"</string>
<string name="adb_wireless_device_details_title" msgid="7129369670526565786">"Түзмөктүн чоо-жайы"</string>
<string name="adb_device_forget" msgid="193072400783068417">"Унутулсун"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index f5e84a23aa07..b9d970d8388f 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -85,7 +85,7 @@
<string name="bluetooth_disconnected" msgid="7739366554710388701">"Не е поврзано"</string>
<string name="bluetooth_disconnecting" msgid="7638892134401574338">"Се исклучува..."</string>
<string name="bluetooth_connecting" msgid="5871702668260192755">"Се поврзува..."</string>
- <string name="bluetooth_connected" msgid="8065345572198502293">"Поврзан со <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_connected" msgid="8065345572198502293">"Поврзано<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_pairing" msgid="4269046942588193600">"Се спарува..."</string>
<string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"Поврзан со <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> (без телефон)"</string>
<string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"Поврзан со <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> (без аудиовизуелни содржини)"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 73b099695da8..ae1df210bce3 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -82,7 +82,7 @@
<string name="speed_label_very_fast" msgid="8215718029533182439">"ଅତି ଦ୍ରୁତ"</string>
<string name="wifi_passpoint_expired" msgid="6540867261754427561">"ମିଆଦ ଶେଷ ହୋଇଯାଇଛି"</string>
<string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
- <string name="bluetooth_disconnected" msgid="7739366554710388701">"ବିଛିନ୍ନ ହେଲା"</string>
+ <string name="bluetooth_disconnected" msgid="7739366554710388701">"ଡିସକନେକ୍ଟ ହୋଇଛି"</string>
<string name="bluetooth_disconnecting" msgid="7638892134401574338">"ବିଚ୍ଛିନ୍ନ କରୁଛି…"</string>
<string name="bluetooth_connecting" msgid="5871702668260192755">"କନେକ୍ଟ ହେଉଛି…"</string>
<string name="bluetooth_connected" msgid="8065345572198502293">"ସଂଯୁକ୍ତ ହେଲା<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 74c294b84db7..4c41b7d4e397 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -82,7 +82,7 @@
<string name="speed_label_very_fast" msgid="8215718029533182439">"Veľmi rýchla"</string>
<string name="wifi_passpoint_expired" msgid="6540867261754427561">"Vypršalo"</string>
<string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
- <string name="bluetooth_disconnected" msgid="7739366554710388701">"Odpojený"</string>
+ <string name="bluetooth_disconnected" msgid="7739366554710388701">"Odpojené"</string>
<string name="bluetooth_disconnecting" msgid="7638892134401574338">"Prebieha odpájanie..."</string>
<string name="bluetooth_connecting" msgid="5871702668260192755">"Prebieha pripájanie…"</string>
<string name="bluetooth_connected" msgid="8065345572198502293">"Pripojené k zariadeniu <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 1c1117d39d5b..1d7f62ac6c93 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -82,7 +82,7 @@
<string name="speed_label_very_fast" msgid="8215718029533182439">"Mycket snabb"</string>
<string name="wifi_passpoint_expired" msgid="6540867261754427561">"Har upphört att gälla"</string>
<string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
- <string name="bluetooth_disconnected" msgid="7739366554710388701">"Kopplas ifrån"</string>
+ <string name="bluetooth_disconnected" msgid="7739366554710388701">"Frånkopplad"</string>
<string name="bluetooth_disconnecting" msgid="7638892134401574338">"Kopplar ifrån…"</string>
<string name="bluetooth_connecting" msgid="5871702668260192755">"Ansluter…"</string>
<string name="bluetooth_connected" msgid="8065345572198502293">"Ansluten<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 57b8f5914e71..060b7b267624 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -82,7 +82,7 @@
<string name="speed_label_very_fast" msgid="8215718029533182439">"เร็วมาก"</string>
<string name="wifi_passpoint_expired" msgid="6540867261754427561">"หมดอายุแล้ว"</string>
<string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
- <string name="bluetooth_disconnected" msgid="7739366554710388701">"ตัดการเชื่อมต่อ"</string>
+ <string name="bluetooth_disconnected" msgid="7739366554710388701">"ยกเลิกการเชื่อมต่อแล้ว"</string>
<string name="bluetooth_disconnecting" msgid="7638892134401574338">"กำลังตัดการเชื่อมต่อ..."</string>
<string name="bluetooth_connecting" msgid="5871702668260192755">"กำลังเชื่อมต่อ…"</string>
<string name="bluetooth_connected" msgid="8065345572198502293">"เชื่อมต่อแล้ว<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingId.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingId.java
index e7c7476d4797..f4b79db67d88 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingId.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingId.java
@@ -120,4 +120,10 @@ public @interface DeviceSettingId {
/** Device setting ID for ANC. */
int DEVICE_SETTING_ID_ANC = 1001;
+
+ /** Device setting expandable ID 1. */
+ int DEVICE_SETTING_ID_EXPANDABLE_1 = 3001;
+
+ /** Device setting expandable ID 2. */
+ int DEVICE_SETTING_ID_EXPANDABLE_2 = 3100;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
index 8537897cb329..c68dbeead26b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
@@ -106,26 +106,40 @@ class DeviceSettingRepositoryImpl(
private fun DeviceSettingsConfig.toModel(): DeviceSettingConfigModel =
DeviceSettingConfigModel(
- mainItems = mainContentItems.map { it.toModel() },
- moreSettingsItems = moreSettingsItems.map { it.toModel() },
+ mainItems = mainContentItems.toModel(),
+ moreSettingsItems = moreSettingsItems.toModel(),
moreSettingsHelpItem = moreSettingsHelpItem?.toModel(),
)
- private fun DeviceSettingItem.toModel(): DeviceSettingConfigItemModel {
+ private fun List<DeviceSettingItem>.toModel(): List<DeviceSettingConfigItemModel> {
+ return this.flatMap { item ->
+ if (item.settingId in EXPANDABLE_SETTING_IDS) {
+ IntRange(item.settingId, item.settingId + SETTING_ID_EXPAND_LIMIT - 1).map {
+ item.toModel(overrideSettingId = it)
+ }
+ } else {
+ listOf(item.toModel())
+ }
+ }
+ }
+
+ private fun DeviceSettingItem.toModel(
+ overrideSettingId: Int? = null
+ ): DeviceSettingConfigItemModel {
return if (!TextUtils.isEmpty(preferenceKey)) {
if (settingId == DeviceSettingId.DEVICE_SETTING_ID_BLUETOOTH_PROFILES) {
BluetoothProfilesItem(
- settingId,
+ overrideSettingId ?: settingId,
highlighted,
preferenceKey!!,
extras.getStringArrayList(DeviceSettingContract.INVISIBLE_PROFILES)
?: emptyList(),
)
} else {
- CommonBuiltinItem(settingId, highlighted, preferenceKey!!)
+ CommonBuiltinItem(overrideSettingId ?: settingId, highlighted, preferenceKey!!)
}
} else {
- AppProvidedItem(settingId, highlighted)
+ AppProvidedItem(overrideSettingId ?: settingId, highlighted)
}
}
@@ -134,6 +148,7 @@ class DeviceSettingRepositoryImpl(
is DeviceSettingIntentAction -> DeviceSettingActionModel.IntentAction(this.intent)
is DeviceSettingPendingIntentAction ->
DeviceSettingActionModel.PendingIntentAction(this.pendingIntent)
+
else -> null
}
@@ -150,7 +165,7 @@ class DeviceSettingRepositoryImpl(
summary = pref.summary,
icon = pref.icon?.let { DeviceSettingIcon.BitmapIcon(it) },
isAllowedChangingState = pref.isAllowedChangingState,
- action = pref.action?.toModel(),
+ action = pref.action.toModel(),
switchState =
if (pref.hasSwitch()) {
DeviceSettingStateModel.ActionSwitchPreferenceState(pref.checked)
@@ -163,6 +178,7 @@ class DeviceSettingRepositoryImpl(
}
},
)
+
is MultiTogglePreference ->
DeviceSettingModel.MultiTogglePreference(
cachedDevice = cachedDevice,
@@ -178,21 +194,33 @@ class DeviceSettingRepositoryImpl(
}
},
)
+
is DeviceSettingFooterPreference ->
DeviceSettingModel.FooterPreference(
cachedDevice = cachedDevice,
id = settingId,
footerText = pref.footerText,
)
+
is DeviceSettingHelpPreference ->
DeviceSettingModel.HelpPreference(
cachedDevice = cachedDevice,
id = settingId,
intent = pref.intent,
)
+
else -> DeviceSettingModel.Unknown(cachedDevice, settingId)
}
private fun ToggleInfo.toModel(): ToggleModel =
ToggleModel(label, DeviceSettingIcon.BitmapIcon(icon))
+
+ companion object {
+ private val EXPANDABLE_SETTING_IDS =
+ listOf(
+ DeviceSettingId.DEVICE_SETTING_ID_EXPANDABLE_1,
+ DeviceSettingId.DEVICE_SETTING_ID_EXPANDABLE_2,
+ )
+ private const val SETTING_ID_EXPAND_LIMIT = 15
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepositoryTest.kt b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepositoryTest.kt
index 4e62fd3b27c5..3d4e4492ffd1 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepositoryTest.kt
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepositoryTest.kt
@@ -167,6 +167,26 @@ class DeviceSettingRepositoryTest {
}
@Test
+ fun getDeviceSettingsConfig_expandable_success() {
+ testScope.runTest {
+ setUpConfigService(true, DEVICE_SETTING_CONFIG_EXPANDABLE)
+ `when`(settingProviderService1.serviceStatus)
+ .thenReturn(DeviceSettingsProviderServiceStatus(true))
+ `when`(settingProviderService2.serviceStatus)
+ .thenReturn(DeviceSettingsProviderServiceStatus(true))
+
+ val config = underTest.getDeviceSettingsConfig(cachedDevice)!!
+
+ assertThat(config.mainItems.map { it.settingId }).isEqualTo(
+ IntRange(
+ DeviceSettingId.DEVICE_SETTING_ID_EXPANDABLE_1,
+ DeviceSettingId.DEVICE_SETTING_ID_EXPANDABLE_1 + 14
+ ).toList()
+ )
+ }
+ }
+
+ @Test
fun getDeviceSettingsConfig_noMetadata_returnNull() {
testScope.runTest {
`when`(
@@ -510,6 +530,13 @@ class DeviceSettingRepositoryTest {
SETTING_PROVIDER_SERVICE_CLASS_NAME_2,
SETTING_PROVIDER_SERVICE_INTENT_ACTION_2,
)
+ val DEVICE_SETTING_APP_PROVIDED_ITEM_EXPANDABLE =
+ DeviceSettingItem(
+ DeviceSettingId.DEVICE_SETTING_ID_EXPANDABLE_1,
+ SETTING_PROVIDER_SERVICE_PACKAGE_NAME_1,
+ SETTING_PROVIDER_SERVICE_CLASS_NAME_1,
+ SETTING_PROVIDER_SERVICE_INTENT_ACTION_1,
+ )
val DEVICE_SETTING_BUILT_IN_ITEM =
DeviceSettingItem(
DeviceSettingId.DEVICE_SETTING_ID_BLUETOOTH_AUDIO_DEVICE_TYPE_GROUP,
@@ -581,5 +608,13 @@ class DeviceSettingRepositoryTest {
listOf(DEVICE_SETTING_APP_PROVIDED_ITEM_2),
DEVICE_SETTING_HELP_ITEM,
)
+ val DEVICE_SETTING_CONFIG_EXPANDABLE =
+ DeviceSettingsConfig(
+ listOf(
+ DEVICE_SETTING_APP_PROVIDED_ITEM_EXPANDABLE,
+ ),
+ listOf(),
+ DEVICE_SETTING_HELP_ITEM,
+ )
}
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 05c5e5d9f82d..1919572ff571 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -951,6 +951,9 @@
<!-- Permission required for CTS test - CtsAppTestCases -->
<uses-permission android:name="android.permission.KILL_UID" />
+ <!-- Permission required for CTS test - CtsTelephonyTestCases -->
+ <uses-permission android:name="android.permission.READ_BASIC_PHONE_STATE" />
+
<application
android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 0537b1454cea..f0e1b437ec51 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -1016,6 +1016,10 @@
android:exported="false">
</activity>
+ <service
+ android:name="com.android.systemui.communal.widgets.GlanceableHubWidgetManagerService"
+ android:exported="false" />
+
<!-- Doze with notifications, run in main sysui process for every user -->
<service
android:name=".doze.DozeService"
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 83b75664e1a6..5c5edb1d00ba 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -26,6 +26,13 @@ flag {
}
flag {
+ name: "modes_ui_dialog_paging"
+ namespace: "systemui"
+ description: "Add pagination to the Modes dialog in quick settings."
+ bug: "376450983"
+}
+
+flag {
name: "priority_people_section"
namespace: "systemui"
description: "Add a new section for priority people (aka important conversations)."
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationScrimNestedScrollConnection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationScrimNestedScrollConnection.kt
index 5cb45e5bd914..94c18cdbef5a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationScrimNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationScrimNestedScrollConnection.kt
@@ -16,11 +16,13 @@
package com.android.systemui.notifications.ui.composable
+import androidx.compose.foundation.gestures.FlingBehavior
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.util.fastCoerceAtLeast
import androidx.compose.ui.util.fastCoerceAtMost
+import com.android.compose.nestedscroll.OnStopScope
import com.android.compose.nestedscroll.PriorityNestedScrollConnection
import com.android.compose.nestedscroll.ScrollController
@@ -43,6 +45,7 @@ fun NotificationScrimNestedScrollConnection(
isCurrentGestureOverscroll: () -> Boolean,
onStart: (Float) -> Unit = {},
onStop: (Float) -> Unit = {},
+ flingBehavior: FlingBehavior,
): PriorityNestedScrollConnection {
return PriorityNestedScrollConnection(
orientation = Orientation.Vertical,
@@ -77,8 +80,9 @@ fun NotificationScrimNestedScrollConnection(
return amountConsumed
}
- override suspend fun onStop(initialVelocity: Float): Float {
- onStop(initialVelocity)
+ override suspend fun OnStopScope.onStop(initialVelocity: Float): Float {
+ val consumedByScroll = flingToScroll(initialVelocity, flingBehavior)
+ onStop(initialVelocity - consumedByScroll)
if (scrimOffset() < minScrimOffset()) {
animateScrimOffset(minScrimOffset())
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackNestedScrollConnection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackNestedScrollConnection.kt
index e1b74a968caa..d8abfd7a4b94 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackNestedScrollConnection.kt
@@ -18,7 +18,9 @@ package com.android.systemui.notifications.ui.composable
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.tween
+import androidx.compose.foundation.gestures.FlingBehavior
import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.ScrollableDefaults
import androidx.compose.foundation.layout.offset
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
@@ -30,6 +32,7 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastCoerceAtLeast
+import com.android.compose.nestedscroll.OnStopScope
import com.android.compose.nestedscroll.PriorityNestedScrollConnection
import com.android.compose.nestedscroll.ScrollController
import kotlin.math.max
@@ -46,32 +49,35 @@ fun Modifier.stackVerticalOverscroll(
val screenHeight =
with(LocalDensity.current) { LocalConfiguration.current.screenHeightDp.dp.toPx() }
val overscrollOffset = remember { Animatable(0f) }
- val stackNestedScrollConnection = remember {
- NotificationStackNestedScrollConnection(
- stackOffset = { overscrollOffset.value },
- canScrollForward = canScrollForward,
- onScroll = { offsetAvailable ->
- coroutineScope.launch {
- val maxProgress = screenHeight * 0.2f
- val tilt = 3f
- var offset =
- overscrollOffset.value +
- maxProgress * tanh(x = offsetAvailable / (maxProgress * tilt))
- offset = max(offset, -1f * maxProgress)
- overscrollOffset.snapTo(offset)
- }
- },
- onStop = { velocityAvailable ->
- coroutineScope.launch {
- overscrollOffset.animateTo(
- targetValue = 0f,
- initialVelocity = velocityAvailable,
- animationSpec = tween(),
- )
- }
- },
- )
- }
+ val flingBehavior = ScrollableDefaults.flingBehavior()
+ val stackNestedScrollConnection =
+ remember(flingBehavior) {
+ NotificationStackNestedScrollConnection(
+ stackOffset = { overscrollOffset.value },
+ canScrollForward = canScrollForward,
+ onScroll = { offsetAvailable ->
+ coroutineScope.launch {
+ val maxProgress = screenHeight * 0.2f
+ val tilt = 3f
+ var offset =
+ overscrollOffset.value +
+ maxProgress * tanh(x = offsetAvailable / (maxProgress * tilt))
+ offset = max(offset, -1f * maxProgress)
+ overscrollOffset.snapTo(offset)
+ }
+ },
+ onStop = { velocityAvailable ->
+ coroutineScope.launch {
+ overscrollOffset.animateTo(
+ targetValue = 0f,
+ initialVelocity = velocityAvailable,
+ animationSpec = tween(),
+ )
+ }
+ },
+ flingBehavior = flingBehavior,
+ )
+ }
return this.then(
Modifier.nestedScroll(stackNestedScrollConnection).offset {
@@ -86,6 +92,7 @@ fun NotificationStackNestedScrollConnection(
onStart: (Float) -> Unit = {},
onScroll: (Float) -> Unit,
onStop: (Float) -> Unit = {},
+ flingBehavior: FlingBehavior,
): PriorityNestedScrollConnection {
return PriorityNestedScrollConnection(
orientation = Orientation.Vertical,
@@ -106,8 +113,9 @@ fun NotificationStackNestedScrollConnection(
return consumed
}
- override suspend fun onStop(initialVelocity: Float): Float {
- onStop(initialVelocity)
+ override suspend fun OnStopScope.onStop(initialVelocity: Float): Float {
+ val consumedByScroll = flingToScroll(initialVelocity, flingBehavior)
+ onStop(initialVelocity - consumedByScroll)
return initialVelocity
}
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 4fa1984661da..ae273d8e2ad9 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
@@ -25,6 +25,7 @@ import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.ScrollableDefaults
import androidx.compose.foundation.gestures.animateScrollBy
import androidx.compose.foundation.gestures.rememberScrollableState
import androidx.compose.foundation.gestures.scrollBy
@@ -451,12 +452,14 @@ fun SceneScope.NotificationScrollingStack(
}
}
+ val flingBehavior = ScrollableDefaults.flingBehavior()
val scrimNestedScrollConnection =
shadeSession.rememberSession(
scrimOffset,
maxScrimTop,
minScrimTop,
isCurrentGestureOverscroll,
+ flingBehavior,
) {
NotificationScrimNestedScrollConnection(
scrimOffset = { scrimOffset.value },
@@ -469,6 +472,7 @@ fun SceneScope.NotificationScrollingStack(
contentHeight = { stackHeight.intValue.toFloat() },
minVisibleScrimHeight = minVisibleScrimHeight,
isCurrentGestureOverscroll = { isCurrentGestureOverscroll.value },
+ flingBehavior = flingBehavior,
)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
index 9d4408aa7acd..46f5ecd99301 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
@@ -121,14 +121,15 @@ private fun Modifier.panelPadding(): Modifier {
val systemBars = WindowInsets.systemBarsIgnoringVisibility
val displayCutout = WindowInsets.displayCutout
val waterfall = WindowInsets.waterfall
- val contentPadding = PaddingValues(all = OverlayShade.Dimensions.ScrimContentPadding)
+ val horizontalPadding =
+ PaddingValues(horizontal = dimensionResource(id = R.dimen.shade_panel_margin_horizontal))
val combinedPadding =
combinePaddings(
systemBars.asPaddingValues(),
displayCutout.asPaddingValues(),
waterfall.asPaddingValues(),
- contentPadding,
+ horizontalPadding,
)
return if (widthSizeClass == WindowWidthSizeClass.Compact) {
@@ -174,7 +175,6 @@ object OverlayShade {
}
object Dimensions {
- val ScrimContentPadding = 16.dp
val PanelCornerRadius = 46.dp
val OverscrollLimit = 32.dp
}
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 7c7202a5c7f2..7872ffad6cec 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
@@ -27,6 +27,7 @@ import androidx.compose.ui.util.fastCoerceIn
import com.android.compose.animation.scene.content.Content
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.animation.scene.content.state.TransitionState.HasOverscrollProperties.Companion.DistanceUnspecified
+import com.android.compose.nestedscroll.OnStopScope
import com.android.compose.nestedscroll.PriorityNestedScrollConnection
import com.android.compose.nestedscroll.ScrollController
import kotlin.math.absoluteValue
@@ -749,7 +750,7 @@ private fun scrollController(
return dragController.onDrag(delta = deltaScroll)
}
- override suspend fun onStop(initialVelocity: Float): Float {
+ override suspend fun OnStopScope.onStop(initialVelocity: Float): Float {
return dragController
.onStop(velocity = initialVelocity, canChangeContent = canChangeScene)
.invoke()
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 b00c8ade07eb..8a6a0d6dbb99 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
@@ -70,6 +70,7 @@ internal fun PredictiveBackHandler(
// The predictive back APIs will automatically animate the progress for us in this case
// so there is no need to animate it.
cancelSpec = snap(),
+ animationScope = layoutImpl.animationScope,
)
}
}
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 715d979e116e..2b33224022fc 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
@@ -30,6 +30,8 @@ import com.android.compose.animation.scene.TransitionKey
import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.createSwipeAnimation
import kotlin.coroutines.cancellation.CancellationException
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collectLatest
@@ -141,6 +143,7 @@ internal suspend fun <T : ContentKey> animateProgress(
progress: Flow<Float>,
commitSpec: AnimationSpec<Float>?,
cancelSpec: AnimationSpec<Float>?,
+ animationScope: CoroutineScope? = null,
) {
fun animateOffset(targetContent: T, spec: AnimationSpec<Float>?) {
if (state.transitionState != animation.contentTransition || animation.isAnimatingOffset()) {
@@ -176,12 +179,20 @@ internal suspend fun <T : ContentKey> animateProgress(
}
// Start the transition.
- state.startTransition(animation.contentTransition)
+ animationScope?.launch { startTransition(state, animation, collectionJob) }
+ ?: startTransition(state, animation, collectionJob)
+ }
+}
- // The transition is done. Cancel the collection in case the transition was finished because
- // it was interrupted by another transition.
- if (collectionJob.isActive) {
- collectionJob.cancel()
- }
+private suspend fun <T : ContentKey> startTransition(
+ state: MutableSceneTransitionLayoutStateImpl,
+ animation: SwipeAnimation<T>,
+ progressCollectionJob: Job,
+) {
+ state.startTransition(animation.contentTransition)
+ // The transition is done. Cancel the collection in case the transition was finished
+ // because it was interrupted by another transition.
+ if (progressCollectionJob.isActive) {
+ progressCollectionJob.cancel()
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt
index 255da31719f3..a5be4dc195bc 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt
@@ -16,6 +16,7 @@
package com.android.compose.nestedscroll
+import androidx.compose.foundation.gestures.FlingBehavior
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
@@ -41,6 +42,7 @@ fun LargeTopAppBarNestedScrollConnection(
onHeightChanged: (Float) -> Unit,
minHeight: () -> Float,
maxHeight: () -> Float,
+ flingBehavior: FlingBehavior,
): PriorityNestedScrollConnection {
return PriorityNestedScrollConnection(
orientation = Orientation.Vertical,
@@ -55,7 +57,15 @@ fun LargeTopAppBarNestedScrollConnection(
offsetAvailable > 0 && height() < maxHeight()
},
canStartPostFling = { false },
- onStart = { LargeTopAppBarScrollController(height, maxHeight, minHeight, onHeightChanged) },
+ onStart = {
+ LargeTopAppBarScrollController(
+ height = height,
+ maxHeight = maxHeight,
+ minHeight = minHeight,
+ onHeightChanged = onHeightChanged,
+ flingBehavior = flingBehavior,
+ )
+ },
)
}
@@ -64,6 +74,7 @@ private class LargeTopAppBarScrollController(
val maxHeight: () -> Float,
val minHeight: () -> Float,
val onHeightChanged: (Float) -> Unit,
+ val flingBehavior: FlingBehavior,
) : ScrollController {
override fun onScroll(deltaScroll: Float, source: NestedScrollSource): Float {
val currentHeight = height()
@@ -79,9 +90,8 @@ private class LargeTopAppBarScrollController(
return amountConsumed
}
- override suspend fun onStop(initialVelocity: Float): Float {
- // Don't consume the velocity on pre/post fling
- return 0f
+ override suspend fun OnStopScope.onStop(initialVelocity: Float): Float {
+ return flingToScroll(initialVelocity, flingBehavior)
}
override fun onCancel() {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
index ca44a5c21cab..e924ebfd2a8d 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
@@ -16,7 +16,9 @@
package com.android.compose.nestedscroll
+import androidx.compose.foundation.gestures.FlingBehavior
import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.ScrollScope
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
@@ -83,7 +85,16 @@ interface ScrollController {
* @param initialVelocity The initial velocity of the scroll when stopping.
* @return The consumed [initialVelocity] when the animation completes.
*/
- suspend fun onStop(initialVelocity: Float): Float
+ suspend fun OnStopScope.onStop(initialVelocity: Float): Float
+}
+
+interface OnStopScope {
+ /**
+ * Emits scroll events by using the [initialVelocity] and the [FlingBehavior].
+ *
+ * @return consumed velocity
+ */
+ suspend fun flingToScroll(initialVelocity: Float, flingBehavior: FlingBehavior): Float
}
/**
@@ -307,7 +318,11 @@ class PriorityNestedScrollConnection(
val controller = requireController(isStopping = false)
return coroutineScope {
try {
- async { controller.onStop(velocity) }
+ async {
+ with(controller) {
+ OnStopScopeImpl(controller = controller).onStop(velocity)
+ }
+ }
// Allows others to interrupt the job.
.also { stoppingJob = it }
// Note: this can be cancelled by [interruptStopping]
@@ -336,3 +351,19 @@ class PriorityNestedScrollConnection(
offsetScrolledBeforePriorityMode = 0f
}
}
+
+private class OnStopScopeImpl(private val controller: ScrollController) : OnStopScope {
+ override suspend fun flingToScroll(
+ initialVelocity: Float,
+ flingBehavior: FlingBehavior,
+ ): Float {
+ return with(flingBehavior) {
+ object : ScrollScope {
+ override fun scrollBy(pixels: Float): Float {
+ return controller.onScroll(pixels, NestedScrollSource.SideEffect)
+ }
+ }
+ .performFling(initialVelocity)
+ }
+ }
+}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt
index a406e13904f5..e27f9b52153d 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt
@@ -16,6 +16,8 @@
package com.android.compose.nestedscroll
+import androidx.compose.foundation.gestures.FlingBehavior
+import androidx.compose.foundation.gestures.ScrollScope
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
@@ -29,6 +31,13 @@ class LargeTopAppBarNestedScrollConnectionTest(testCase: TestCase) {
val scrollSource = testCase.scrollSource
private var height = 0f
+ private val customFlingBehavior =
+ object : FlingBehavior {
+ override suspend fun ScrollScope.performFling(initialVelocity: Float): Float {
+ scrollBy(initialVelocity)
+ return initialVelocity / 2f
+ }
+ }
private fun buildScrollConnection(heightRange: ClosedFloatingPointRange<Float>) =
LargeTopAppBarNestedScrollConnection(
@@ -36,6 +45,7 @@ class LargeTopAppBarNestedScrollConnectionTest(testCase: TestCase) {
onHeightChanged = { height = it },
minHeight = { heightRange.start },
maxHeight = { heightRange.endInclusive },
+ flingBehavior = customFlingBehavior,
)
private fun NestedScrollConnection.scroll(
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
index 0364cdc4166e..54428404bd0c 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
@@ -18,12 +18,15 @@
package com.android.compose.nestedscroll
+import androidx.compose.foundation.gestures.FlingBehavior
import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.ScrollScope
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.NestedScrollSource.Companion.UserInput
import androidx.compose.ui.unit.Velocity
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.test.runMonotonicClockTest
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
@@ -41,7 +44,16 @@ class PriorityNestedScrollConnectionTest {
private var consumeScroll = true
private var lastStop: Float? = null
private var isCancelled: Boolean = false
- private var consumeStop = true
+ private var onStopConsumeFlingToScroll = false
+ private var onStopConsumeAll = true
+
+ private val customFlingBehavior =
+ object : FlingBehavior {
+ override suspend fun ScrollScope.performFling(initialVelocity: Float): Float {
+ scrollBy(initialVelocity)
+ return initialVelocity / 2f
+ }
+ }
private val scrollConnection =
PriorityNestedScrollConnection(
@@ -57,9 +69,16 @@ class PriorityNestedScrollConnectionTest {
return if (consumeScroll) deltaScroll else 0f
}
- override suspend fun onStop(initialVelocity: Float): Float {
+ override suspend fun OnStopScope.onStop(initialVelocity: Float): Float {
lastStop = initialVelocity
- return if (consumeStop) initialVelocity else 0f
+ var velocityConsumed = 0f
+ if (onStopConsumeFlingToScroll) {
+ velocityConsumed = flingToScroll(initialVelocity, customFlingBehavior)
+ }
+ if (onStopConsumeAll) {
+ velocityConsumed = initialVelocity
+ }
+ return velocityConsumed
}
override fun onCancel() {
@@ -178,6 +197,22 @@ class PriorityNestedScrollConnectionTest {
}
@Test
+ fun onStopScrollUsingFlingToScroll() = runMonotonicClockTest {
+ startPriorityModePostScroll()
+ onStopConsumeFlingToScroll = true
+ onStopConsumeAll = false
+ lastScroll = Float.NaN
+
+ val consumed = scrollConnection.onPreFling(available = Velocity(2f, 2f))
+
+ assertThat(lastStop).isEqualTo(2f)
+ // flingToScroll should try to scroll the content, customFlingBehavior uses the velocity.
+ assertThat(lastScroll).isEqualTo(2f)
+ // customFlingBehavior returns half of the vertical velocity.
+ assertThat(consumed).isEqualTo(Velocity(0f, 1f))
+ }
+
+ @Test
fun ifCannotStopOnPreFling_shouldStopOnPostFling() = runTest {
startPriorityModePostScroll()
canStopOnPreFling = false
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryLocalImplTest.kt
index 8ae9d2e8f7e8..55d7d08e8519 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryLocalImplTest.kt
@@ -73,7 +73,7 @@ import org.mockito.kotlin.whenever
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
-class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
+class CommunalWidgetRepositoryLocalImplTest : SysuiTestCase() {
@Mock private lateinit var appWidgetHost: CommunalAppWidgetHost
@Mock private lateinit var providerInfoA: AppWidgetProviderInfo
@Mock private lateinit var providerInfoB: AppWidgetProviderInfo
@@ -105,14 +105,14 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
"com.android.fake/WidgetProviderC",
)
- private lateinit var underTest: CommunalWidgetRepositoryImpl
+ private lateinit var underTest: CommunalWidgetRepositoryLocalImpl
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
fakeWidgets = MutableStateFlow(emptyMap())
fakeProviders = MutableStateFlow(emptyMap())
- logBuffer = logcatLogBuffer(name = "CommunalWidgetRepoImplTest")
+ logBuffer = logcatLogBuffer(name = "CommunalWidgetRepoLocalImplTest")
backupUtils = CommunalBackupUtils(kosmos.applicationContext)
setAppWidgetIds(emptyList())
@@ -126,7 +126,7 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
restoreUser(mainUser)
underTest =
- CommunalWidgetRepositoryImpl(
+ CommunalWidgetRepositoryLocalImpl(
appWidgetHost,
testScope.backgroundScope,
kosmos.testDispatcher,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/shared/model/CommunalWidgetContentModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/shared/model/CommunalWidgetContentModelTest.kt
new file mode 100644
index 000000000000..c21015402f01
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/shared/model/CommunalWidgetContentModelTest.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.shared.model
+
+import android.appwidget.AppWidgetProviderInfo
+import android.content.ComponentName
+import android.os.Parcel
+import android.os.UserHandle
+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 CommunalWidgetContentModelTest : SysuiTestCase() {
+ @Test
+ fun testParcelizeAvailableWidget() {
+ val widgetToParcelize =
+ CommunalWidgetContentModel.Available(
+ appWidgetId = 1,
+ providerInfo =
+ AppWidgetProviderInfo().apply { provider = ComponentName("pkg", "cls") },
+ rank = 2,
+ spanY = 3,
+ )
+
+ val parcel = Parcel.obtain()
+ widgetToParcelize.writeToParcel(parcel, flags = 0)
+
+ parcel.setDataPosition(0)
+
+ // Only checking fields are equal and not complete equality because not all fields are
+ // specified in the fake AppWidgetProviderInfo
+ val widgetFromParcel =
+ CommunalWidgetContentModel.createFromParcel(parcel)
+ as CommunalWidgetContentModel.Available
+ assertThat(widgetFromParcel.appWidgetId).isEqualTo(widgetToParcelize.appWidgetId)
+ assertThat(widgetFromParcel.rank).isEqualTo(widgetToParcelize.rank)
+ assertThat(widgetFromParcel.spanY).isEqualTo(widgetToParcelize.spanY)
+ assertThat(widgetFromParcel.providerInfo.provider)
+ .isEqualTo(widgetToParcelize.providerInfo.provider)
+ }
+
+ @Test
+ fun testParcelizePendingWidget() {
+ val widgetToParcelize =
+ CommunalWidgetContentModel.Pending(
+ appWidgetId = 2,
+ rank = 3,
+ componentName = ComponentName("pkg", "cls"),
+ icon = null,
+ user = UserHandle(0),
+ spanY = 6,
+ )
+
+ val parcel = Parcel.obtain()
+ widgetToParcelize.writeToParcel(parcel, flags = 0)
+
+ parcel.setDataPosition(0)
+
+ val widgetFromParcel = CommunalWidgetContentModel.createFromParcel(parcel)
+ assertThat(widgetFromParcel).isEqualTo(widgetToParcelize)
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/widgets/CommunalAppWidgetHostTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/widgets/CommunalAppWidgetHostTest.kt
index 1e79112eefe3..18513fc496b4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/widgets/CommunalAppWidgetHostTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/widgets/CommunalAppWidgetHostTest.kt
@@ -21,6 +21,7 @@ import android.testing.TestableLooper.RunWithLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.shared.model.fakeGlanceableHubMultiUserHelper
import com.android.systemui.communal.widgets.CommunalAppWidgetHost
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.applicationCoroutineScope
@@ -61,6 +62,7 @@ class CommunalAppWidgetHostTest : SysuiTestCase() {
backgroundScope = kosmos.applicationCoroutineScope,
hostId = 116,
logBuffer = logcatLogBuffer("CommunalAppWidgetHostTest"),
+ glanceableHubMultiUserHelper = kosmos.fakeGlanceableHubMultiUserHelper,
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt
index c9f3f1453492..9ef2b190fdd7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt
@@ -24,10 +24,14 @@ import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository
import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
+import com.android.systemui.communal.shared.model.FakeGlanceableHubMultiUserHelper
+import com.android.systemui.communal.shared.model.fakeGlanceableHubMultiUserHelper
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.Flags
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
@@ -58,6 +62,9 @@ class CommunalAppWidgetHostStartableTest : SysuiTestCase() {
@Mock private lateinit var appWidgetHost: CommunalAppWidgetHost
@Mock private lateinit var communalWidgetHost: CommunalWidgetHost
+ private lateinit var widgetManager: GlanceableHubWidgetManager
+ private lateinit var helper: FakeGlanceableHubMultiUserHelper
+
private lateinit var appWidgetIdToRemove: MutableSharedFlow<Int>
private lateinit var underTest: CommunalAppWidgetHostStartable
@@ -69,17 +76,23 @@ class CommunalAppWidgetHostStartableTest : SysuiTestCase() {
kosmos.fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, true)
mSetFlagsRule.enableFlags(FLAG_COMMUNAL_HUB)
+ widgetManager = kosmos.mockGlanceableHubWidgetManager
+ helper = kosmos.fakeGlanceableHubMultiUserHelper
appWidgetIdToRemove = MutableSharedFlow()
whenever(appWidgetHost.appWidgetIdToRemove).thenReturn(appWidgetIdToRemove)
underTest =
CommunalAppWidgetHostStartable(
- appWidgetHost,
- communalWidgetHost,
- kosmos.communalInteractor,
- kosmos.fakeUserTracker,
+ { appWidgetHost },
+ { communalWidgetHost },
+ { kosmos.communalInteractor },
+ { kosmos.communalSettingsInteractor },
+ { kosmos.keyguardInteractor },
+ { kosmos.fakeUserTracker },
kosmos.applicationCoroutineScope,
kosmos.testDispatcher,
+ { widgetManager },
+ helper,
)
}
@@ -211,7 +224,7 @@ class CommunalAppWidgetHostStartableTest : SysuiTestCase() {
fakeCommunalWidgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id)
fakeCommunalWidgetRepository.addPendingWidget(
appWidgetId = 2,
- userId = USER_INFO_WORK.id
+ userId = USER_INFO_WORK.id,
)
fakeCommunalWidgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id)
@@ -246,16 +259,42 @@ class CommunalAppWidgetHostStartableTest : SysuiTestCase() {
}
}
- private suspend fun setCommunalAvailable(available: Boolean) =
+ @Test
+ fun onStartHeadlessSystemUser_registerWidgetManager_whenCommunalIsAvailable() =
+ with(kosmos) {
+ testScope.runTest {
+ helper.setIsInHeadlessSystemUser(true)
+ underTest.start()
+ runCurrent()
+ verify(widgetManager, never()).register()
+ verify(widgetManager, never()).unregister()
+
+ // Binding to the service does not require keyguard showing
+ setCommunalAvailable(true, setKeyguardShowing = false)
+ runCurrent()
+ verify(widgetManager).register()
+
+ setCommunalAvailable(false)
+ runCurrent()
+ verify(widgetManager).unregister()
+ }
+ }
+
+ private suspend fun setCommunalAvailable(
+ available: Boolean,
+ setKeyguardShowing: Boolean = true,
+ ) =
with(kosmos) {
fakeKeyguardRepository.setIsEncryptedOrLockdown(false)
fakeUserRepository.setSelectedUserInfo(MAIN_USER_INFO)
- fakeKeyguardRepository.setKeyguardShowing(true)
+ if (setKeyguardShowing) {
+ fakeKeyguardRepository.setKeyguardShowing(true)
+ }
val settingsValue = if (available) 1 else 0
fakeSettings.putIntForUser(
Settings.Secure.GLANCEABLE_HUB_ENABLED,
settingsValue,
- MAIN_USER_INFO.id
+ MAIN_USER_INFO.id,
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt
index 054e516db943..017c77828cdc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt
@@ -26,6 +26,7 @@ import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.shared.model.fakeGlanceableHubMultiUserHelper
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.kosmos.applicationCoroutineScope
@@ -84,7 +85,7 @@ class CommunalWidgetHostTest : SysuiTestCase() {
any<Int>(),
any<UserHandle>(),
any<ComponentName>(),
- any<Bundle>()
+ any<Bundle>(),
)
)
.thenReturn(true)
@@ -96,6 +97,7 @@ class CommunalWidgetHostTest : SysuiTestCase() {
appWidgetHost,
selectedUserInteractor,
logcatLogBuffer("CommunalWidgetHostTest"),
+ glanceableHubMultiUserHelper = kosmos.fakeGlanceableHubMultiUserHelper,
)
}
@@ -162,7 +164,7 @@ class CommunalWidgetHostTest : SysuiTestCase() {
any<Int>(),
any<UserHandle>(),
any<ComponentName>(),
- any<Bundle>()
+ any<Bundle>(),
)
)
.thenReturn(false)
@@ -283,12 +285,7 @@ class CommunalWidgetHostTest : SysuiTestCase() {
// all providers are emitted at once
assertThat(providerInfoValues).hasSize(2)
assertThat(providerInfoValues[1])
- .containsExactlyEntriesIn(
- mapOf(
- Pair(1, providerInfo1),
- Pair(2, providerInfo2),
- )
- )
+ .containsExactlyEntriesIn(mapOf(Pair(1, providerInfo1), Pair(2, providerInfo2)))
}
@Test
@@ -304,12 +301,7 @@ class CommunalWidgetHostTest : SysuiTestCase() {
// Assert that the provider info map is populated
val providerInfo by collectLastValue(underTest.appWidgetProviders)
assertThat(providerInfo)
- .containsExactlyEntriesIn(
- mapOf(
- Pair(1, providerInfo1),
- Pair(2, providerInfo2),
- )
- )
+ .containsExactlyEntriesIn(mapOf(Pair(1, providerInfo1), Pair(2, providerInfo2)))
// Host stop listening
observer.onHostStopListening()
@@ -332,12 +324,7 @@ class CommunalWidgetHostTest : SysuiTestCase() {
// Assert that the provider info map is populated
assertThat(providerInfo)
- .containsExactlyEntriesIn(
- mapOf(
- Pair(1, providerInfo1),
- Pair(2, providerInfo2),
- )
- )
+ .containsExactlyEntriesIn(mapOf(Pair(1, providerInfo1), Pair(2, providerInfo2)))
// Provider info for widget 1 updated
val listener =
@@ -349,12 +336,7 @@ class CommunalWidgetHostTest : SysuiTestCase() {
// Assert that the update is reflected in the flow
assertThat(providerInfo)
- .containsExactlyEntriesIn(
- mapOf(
- Pair(1, providerInfo3),
- Pair(2, providerInfo2),
- )
- )
+ .containsExactlyEntriesIn(mapOf(Pair(1, providerInfo3), Pair(2, providerInfo2)))
}
@Test
@@ -371,12 +353,7 @@ class CommunalWidgetHostTest : SysuiTestCase() {
// Assert that the provider info map is populated
assertThat(providerInfo)
- .containsExactlyEntriesIn(
- mapOf(
- Pair(1, providerInfo1),
- Pair(2, providerInfo2),
- )
- )
+ .containsExactlyEntriesIn(mapOf(Pair(1, providerInfo1), Pair(2, providerInfo2)))
// Bind a new widget
whenever(appWidgetHost.allocateAppWidgetId()).thenReturn(3)
@@ -388,11 +365,7 @@ class CommunalWidgetHostTest : SysuiTestCase() {
// Assert that the new provider is reflected in the flow
assertThat(providerInfo)
.containsExactlyEntriesIn(
- mapOf(
- Pair(1, providerInfo1),
- Pair(2, providerInfo2),
- Pair(3, providerInfo3),
- )
+ mapOf(Pair(1, providerInfo1), Pair(2, providerInfo2), Pair(3, providerInfo3))
)
}
@@ -410,31 +383,21 @@ class CommunalWidgetHostTest : SysuiTestCase() {
// Assert that the provider info map is populated
assertThat(providerInfo)
- .containsExactlyEntriesIn(
- mapOf(
- Pair(1, providerInfo1),
- Pair(2, providerInfo2),
- )
- )
+ .containsExactlyEntriesIn(mapOf(Pair(1, providerInfo1), Pair(2, providerInfo2)))
// Remove widget 1
observer.onDeleteAppWidgetId(1)
runCurrent()
// Assert that provider info for widget 1 is removed
- assertThat(providerInfo)
- .containsExactlyEntriesIn(
- mapOf(
- Pair(2, providerInfo2),
- )
- )
+ assertThat(providerInfo).containsExactlyEntriesIn(mapOf(Pair(2, providerInfo2)))
}
private fun selectUser() {
kosmos.fakeUserRepository.selectedUser.value =
SelectedUserModel(
userInfo = UserInfo(0, "Current user", 0),
- selectionStatus = SelectionStatus.SELECTION_COMPLETE
+ selectionStatus = SelectionStatus.SELECTION_COMPLETE,
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceTest.kt
new file mode 100644
index 000000000000..44ce08514dee
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceTest.kt
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.widgets
+
+import android.appwidget.AppWidgetHost
+import android.appwidget.AppWidgetProviderInfo
+import android.content.ComponentName
+import android.content.Intent
+import android.os.UserHandle
+import android.testing.TestableLooper
+import android.widget.RemoteViews
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository
+import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
+import com.android.systemui.communal.shared.model.fakeGlanceableHubMultiUserHelper
+import com.android.systemui.communal.widgets.IGlanceableHubWidgetManagerService.IGlanceableHubWidgetsListener
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.log.logcatLogBuffer
+import com.android.systemui.testKosmos
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.awaitClose
+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.argumentCaptor
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@RunWith(AndroidJUnit4::class)
+class GlanceableHubWidgetManagerServiceTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+
+ private val appWidgetHostListenerCaptor = argumentCaptor<AppWidgetHost.AppWidgetHostListener>()
+
+ private val widgetRepository = kosmos.fakeCommunalWidgetRepository
+ private val appWidgetHost = mock<CommunalAppWidgetHost>()
+ private val communalWidgetHost = mock<CommunalWidgetHost>()
+ private val multiUserHelper = kosmos.fakeGlanceableHubMultiUserHelper
+
+ private lateinit var underTest: GlanceableHubWidgetManagerService
+
+ @Before
+ fun setup() {
+ underTest =
+ GlanceableHubWidgetManagerService(
+ widgetRepository,
+ appWidgetHost,
+ communalWidgetHost,
+ multiUserHelper,
+ logcatLogBuffer("GlanceableHubWidgetManagerServiceTest"),
+ )
+ }
+
+ @Test
+ fun appWidgetHost_listenWhenServiceIsBound() {
+ underTest.onCreate()
+ verify(appWidgetHost).startListening()
+ verify(communalWidgetHost).startObservingHost()
+ verify(appWidgetHost, never()).stopListening()
+ verify(communalWidgetHost, never()).stopObservingHost()
+
+ underTest.onDestroy()
+ verify(appWidgetHost).stopListening()
+ verify(communalWidgetHost).stopObservingHost()
+ }
+
+ @Test
+ fun widgetsListener_getWidgetUpdates() =
+ testScope.runTest {
+ setupWidgets()
+
+ // Bind service
+ val binder = underTest.onBind(Intent())
+ val service = IGlanceableHubWidgetManagerService.Stub.asInterface(binder)
+
+ // Verify the update is as expected
+ val widgets by collectLastValue(service.listenForWidgetUpdates())
+ assertThat(widgets).hasSize(3)
+ assertThat(widgets?.get(0)?.has(1, "pkg_1/cls_1", 0, 3)).isTrue()
+ assertThat(widgets?.get(1)?.has(2, "pkg_2/cls_2", 1, 3)).isTrue()
+ assertThat(widgets?.get(2)?.has(3, "pkg_3/cls_3", 2, 6)).isTrue()
+ }
+
+ @Test
+ fun widgetsListener_multipleListeners_eachGetsWidgetUpdates() =
+ testScope.runTest {
+ setupWidgets()
+
+ // Bind service
+ val binder = underTest.onBind(Intent())
+ val service = IGlanceableHubWidgetManagerService.Stub.asInterface(binder)
+
+ // Verify the update for the first listener is as expected
+ val widgets1 by collectLastValue(service.listenForWidgetUpdates())
+ assertThat(widgets1).hasSize(3)
+ assertThat(widgets1?.get(0)?.has(1, "pkg_1/cls_1", 0, 3)).isTrue()
+ assertThat(widgets1?.get(1)?.has(2, "pkg_2/cls_2", 1, 3)).isTrue()
+ assertThat(widgets1?.get(2)?.has(3, "pkg_3/cls_3", 2, 6)).isTrue()
+
+ // Verify the update for the second listener is as expected
+ val widgets2 by collectLastValue(service.listenForWidgetUpdates())
+ assertThat(widgets2).hasSize(3)
+ assertThat(widgets2?.get(0)?.has(1, "pkg_1/cls_1", 0, 3)).isTrue()
+ assertThat(widgets2?.get(1)?.has(2, "pkg_2/cls_2", 1, 3)).isTrue()
+ assertThat(widgets2?.get(2)?.has(3, "pkg_3/cls_3", 2, 6)).isTrue()
+ }
+
+ @Test
+ fun setAppWidgetHostListener_getUpdates() =
+ testScope.runTest {
+ // Bind service
+ val binder = underTest.onBind(Intent())
+ val service = IGlanceableHubWidgetManagerService.Stub.asInterface(binder)
+
+ // Set listener
+ val listener = mock<IGlanceableHubWidgetManagerService.IAppWidgetHostListener>()
+ service.setAppWidgetHostListener(1, listener)
+
+ // Verify a listener is set on the host
+ verify(appWidgetHost).setListener(eq(1), appWidgetHostListenerCaptor.capture())
+ val appWidgetHostListener = appWidgetHostListenerCaptor.firstValue
+
+ // Each update should be passed to the listener
+ val providerInfo = mock<AppWidgetProviderInfo>()
+ appWidgetHostListener.onUpdateProviderInfo(providerInfo)
+ verify(listener).onUpdateProviderInfo(providerInfo)
+
+ val remoteViews = mock<RemoteViews>()
+ appWidgetHostListener.updateAppWidget(remoteViews)
+ verify(listener).updateAppWidget(remoteViews)
+
+ appWidgetHostListener.updateAppWidgetDeferred("pkg", 1)
+ verify(listener).updateAppWidgetDeferred("pkg", 1)
+
+ appWidgetHostListener.onViewDataChanged(1)
+ verify(listener).onViewDataChanged(1)
+ }
+
+ @Test
+ fun addWidget_getWidgetUpdate() =
+ testScope.runTest {
+ setupWidgets()
+
+ // Bind service
+ val binder = underTest.onBind(Intent())
+ val service = IGlanceableHubWidgetManagerService.Stub.asInterface(binder)
+
+ // Verify the update is as expected
+ val widgets by collectLastValue(service.listenForWidgetUpdates())
+ assertThat(widgets).hasSize(3)
+ assertThat(widgets?.get(0)?.has(1, "pkg_1/cls_1", 0, 3)).isTrue()
+ assertThat(widgets?.get(1)?.has(2, "pkg_2/cls_2", 1, 3)).isTrue()
+ assertThat(widgets?.get(2)?.has(3, "pkg_3/cls_3", 2, 6)).isTrue()
+
+ // Add a widget
+ service.addWidget(ComponentName("pkg_4", "cls_4"), UserHandle.of(0), 3)
+ runCurrent()
+
+ // Verify an update pushed with widget 4 added
+ assertThat(widgets).hasSize(4)
+ assertThat(widgets?.get(0)?.has(1, "pkg_1/cls_1", 0, 3)).isTrue()
+ assertThat(widgets?.get(1)?.has(2, "pkg_2/cls_2", 1, 3)).isTrue()
+ assertThat(widgets?.get(2)?.has(3, "pkg_3/cls_3", 2, 6)).isTrue()
+ assertThat(widgets?.get(3)?.has(4, "pkg_4/cls_4", 3, 3)).isTrue()
+ }
+
+ @Test
+ fun deleteWidget_getWidgetUpdate() =
+ testScope.runTest {
+ setupWidgets()
+
+ // Bind service
+ val binder = underTest.onBind(Intent())
+ val service = IGlanceableHubWidgetManagerService.Stub.asInterface(binder)
+
+ // Verify the update is as expected
+ val widgets by collectLastValue(service.listenForWidgetUpdates())
+ assertThat(widgets).hasSize(3)
+ assertThat(widgets?.get(0)?.has(1, "pkg_1/cls_1", 0, 3)).isTrue()
+ assertThat(widgets?.get(1)?.has(2, "pkg_2/cls_2", 1, 3)).isTrue()
+ assertThat(widgets?.get(2)?.has(3, "pkg_3/cls_3", 2, 6)).isTrue()
+
+ // Delete a widget
+ service.deleteWidget(1)
+ runCurrent()
+
+ // Verify an update pushed with widget 1 removed
+ assertThat(widgets).hasSize(2)
+ assertThat(widgets?.get(0)?.has(2, "pkg_2/cls_2", 1, 3)).isTrue()
+ assertThat(widgets?.get(1)?.has(3, "pkg_3/cls_3", 2, 6)).isTrue()
+ }
+
+ @Test
+ fun updateWidgetOrder_getWidgetUpdate() =
+ testScope.runTest {
+ setupWidgets()
+
+ // Bind service
+ val binder = underTest.onBind(Intent())
+ val service = IGlanceableHubWidgetManagerService.Stub.asInterface(binder)
+
+ // Verify the update is as expected
+ val widgets by collectLastValue(service.listenForWidgetUpdates())
+ assertThat(widgets).hasSize(3)
+ assertThat(widgets?.get(0)?.has(1, "pkg_1/cls_1", 0, 3)).isTrue()
+ assertThat(widgets?.get(1)?.has(2, "pkg_2/cls_2", 1, 3)).isTrue()
+ assertThat(widgets?.get(2)?.has(3, "pkg_3/cls_3", 2, 6)).isTrue()
+
+ // Update widget order
+ service.updateWidgetOrder(intArrayOf(1, 2, 3), intArrayOf(2, 1, 0))
+ runCurrent()
+
+ // Verify an update pushed with the new order
+ assertThat(widgets).hasSize(3)
+ assertThat(widgets?.get(0)?.has(3, "pkg_3/cls_3", 0, 6)).isTrue()
+ assertThat(widgets?.get(1)?.has(2, "pkg_2/cls_2", 1, 3)).isTrue()
+ assertThat(widgets?.get(2)?.has(1, "pkg_1/cls_1", 2, 3)).isTrue()
+ }
+
+ @Test
+ fun resizeWidget_getWidgetUpdate() =
+ testScope.runTest {
+ setupWidgets()
+
+ // Bind service
+ val binder = underTest.onBind(Intent())
+ val service = IGlanceableHubWidgetManagerService.Stub.asInterface(binder)
+
+ // Verify the update is as expected
+ val widgets by collectLastValue(service.listenForWidgetUpdates())
+ assertThat(widgets).hasSize(3)
+ assertThat(widgets?.get(0)?.has(1, "pkg_1/cls_1", 0, 3)).isTrue()
+ assertThat(widgets?.get(1)?.has(2, "pkg_2/cls_2", 1, 3)).isTrue()
+ assertThat(widgets?.get(2)?.has(3, "pkg_3/cls_3", 2, 6)).isTrue()
+
+ // Resize widget 1 from spanY 3 to 6
+ service.resizeWidget(1, 6, intArrayOf(1, 2, 3), intArrayOf(0, 1, 2))
+ runCurrent()
+
+ // Verify an update pushed with the new size for widget 1
+ assertThat(widgets).hasSize(3)
+ assertThat(widgets?.get(0)?.has(1, "pkg_1/cls_1", 0, 6)).isTrue()
+ assertThat(widgets?.get(1)?.has(2, "pkg_2/cls_2", 1, 3)).isTrue()
+ assertThat(widgets?.get(2)?.has(3, "pkg_3/cls_3", 2, 6)).isTrue()
+ }
+
+ private fun setupWidgets() {
+ widgetRepository.addWidget(
+ appWidgetId = 1,
+ componentName = "pkg_1/cls_1",
+ rank = 0,
+ spanY = 3,
+ )
+ widgetRepository.addWidget(
+ appWidgetId = 2,
+ componentName = "pkg_2/cls_2",
+ rank = 1,
+ spanY = 3,
+ )
+ widgetRepository.addWidget(
+ appWidgetId = 3,
+ componentName = "pkg_3/cls_3",
+ rank = 2,
+ spanY = 6,
+ )
+ }
+
+ private fun IGlanceableHubWidgetManagerService.listenForWidgetUpdates() =
+ conflatedCallbackFlow<List<CommunalWidgetContentModel>> {
+ val listener =
+ object : IGlanceableHubWidgetsListener.Stub() {
+ override fun onWidgetsUpdated(widgets: List<CommunalWidgetContentModel>) {
+ trySend(widgets)
+ }
+ }
+ addWidgetsListener(listener)
+ awaitClose { removeWidgetsListener(listener) }
+ }
+
+ private fun CommunalWidgetContentModel.has(
+ appWidgetId: Int,
+ componentName: String,
+ rank: Int,
+ spanY: Int,
+ ): Boolean {
+ return this is CommunalWidgetContentModel.Available &&
+ this.appWidgetId == appWidgetId &&
+ this.providerInfo.provider.flattenToString() == componentName &&
+ this.rank == rank &&
+ this.spanY == spanY
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetConfigurationControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetConfigurationControllerTest.kt
index 55fafdff795f..5d4eaf07be25 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetConfigurationControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetConfigurationControllerTest.kt
@@ -22,6 +22,7 @@ import androidx.activity.ComponentActivity
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.shared.model.fakeGlanceableHubMultiUserHelper
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
@@ -55,7 +56,12 @@ class WidgetConfigurationControllerTest : SysuiTestCase() {
fun setUp() {
MockitoAnnotations.initMocks(this)
underTest =
- WidgetConfigurationController(ownerActivity, appWidgetHost, kosmos.testDispatcher)
+ WidgetConfigurationController(
+ ownerActivity,
+ { appWidgetHost },
+ kosmos.testDispatcher,
+ kosmos.fakeGlanceableHubMultiUserHelper,
+ )
}
@Test
@@ -68,7 +74,7 @@ class WidgetConfigurationControllerTest : SysuiTestCase() {
eq(123),
anyInt(),
eq(WidgetConfigurationController.REQUEST_CODE),
- any()
+ any(),
)
)
.thenThrow(ActivityNotFoundException())
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepositoryTest.kt
index 9e20e7d0f98c..620b8b63c71a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepositoryTest.kt
@@ -16,7 +16,11 @@
package com.android.systemui.keyboard.shortcut.data.repository
+import android.graphics.drawable.Drawable
+import android.hardware.input.KeyGlyphMap
import android.hardware.input.fakeInputManager
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.view.KeyEvent.KEYCODE_1
import android.view.KeyEvent.KEYCODE_A
import android.view.KeyEvent.KEYCODE_B
@@ -26,10 +30,12 @@ import android.view.KeyEvent.KEYCODE_E
import android.view.KeyEvent.KEYCODE_F
import android.view.KeyEvent.KEYCODE_G
import android.view.KeyEvent.META_FUNCTION_ON
+import android.view.KeyEvent.META_META_ON
import android.view.KeyboardShortcutGroup
import android.view.KeyboardShortcutInfo
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_SHORTCUT_HELPER_KEY_GLYPH
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyboard.shortcut.data.source.FakeKeyboardShortcutGroupsSource
@@ -49,6 +55,7 @@ import com.android.systemui.keyboard.shortcut.shortcutHelperSystemShortcutsSourc
import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -57,6 +64,9 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mockito.mock
+import org.mockito.kotlin.whenever
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@@ -187,6 +197,79 @@ class ShortcutHelperCategoriesRepositoryTest : SysuiTestCase() {
)
}
+ @EnableFlags(FLAG_SHORTCUT_HELPER_KEY_GLYPH)
+ @Test
+ fun modifierMappedToCustomDrawableWhenKeyGlyphMapExists() =
+ testScope.runTest {
+ val metaDrawable = mock(Drawable::class.java)
+ val keyGlyph = mock(KeyGlyphMap::class.java)
+ whenever(keyGlyph.getDrawableForModifierState(context, META_META_ON))
+ .thenReturn(metaDrawable)
+ whenever(kosmos.fakeInputManager.inputManager.getKeyGlyphMap(anyInt()))
+ .thenReturn(keyGlyph)
+ fakeSystemSource.setGroups(simpleGroup(simpleShortcutInfo(KEYCODE_1, META_META_ON)))
+ helper.toggle(deviceId = 123)
+
+ val categories by collectLastValue(repo.categories)
+ val systemCategory = categories?.firstOrNull { it.type == ShortcutCategoryType.System }
+
+ val expectedCategory =
+ ShortcutCategory(
+ type = ShortcutCategoryType.System,
+ simpleSubCategory(
+ simpleDrawableModifierShortcut("1", modifierDrawable = metaDrawable)
+ ),
+ )
+
+ assertThat(systemCategory).isEqualTo(expectedCategory)
+ }
+
+ @EnableFlags(FLAG_SHORTCUT_HELPER_KEY_GLYPH)
+ @Test
+ fun modifierMappedToDefaultDrawableWhenNoKeyGlyphMapExists() =
+ testScope.runTest {
+ fakeSystemSource.setGroups(simpleGroup(simpleShortcutInfo(KEYCODE_1, META_META_ON)))
+ helper.toggle(deviceId = 123)
+
+ val categories by collectLastValue(repo.categories)
+ val systemCategory = categories?.firstOrNull { it.type == ShortcutCategoryType.System }
+
+ val expectedCategory =
+ ShortcutCategory(
+ type = ShortcutCategoryType.System,
+ simpleSubCategory(
+ simpleResIdModifierShortcut("1", modifierResId = R.drawable.ic_ksh_key_meta)
+ ),
+ )
+ assertThat(systemCategory).isEqualTo(expectedCategory)
+ }
+
+ @DisableFlags(FLAG_SHORTCUT_HELPER_KEY_GLYPH)
+ @Test
+ fun modifierMappedToDefaultDrawableWhenKeyGlyphDisabled() =
+ testScope.runTest {
+ val metaDrawable = mock(Drawable::class.java)
+ val keyGlyph = mock(KeyGlyphMap::class.java)
+ whenever(keyGlyph.getDrawableForModifierState(context, META_META_ON))
+ .thenReturn(metaDrawable)
+ whenever(kosmos.fakeInputManager.inputManager.getKeyGlyphMap(anyInt()))
+ .thenReturn(keyGlyph)
+ fakeSystemSource.setGroups(simpleGroup(simpleShortcutInfo(KEYCODE_1, META_META_ON)))
+ helper.toggle(deviceId = 123)
+
+ val categories by collectLastValue(repo.categories)
+ val systemCategory = categories?.firstOrNull { it.type == ShortcutCategoryType.System }
+
+ val expectedCategory =
+ ShortcutCategory(
+ type = ShortcutCategoryType.System,
+ simpleSubCategory(
+ simpleResIdModifierShortcut("1", modifierResId = R.drawable.ic_ksh_key_meta)
+ ),
+ )
+ assertThat(systemCategory).isEqualTo(expectedCategory)
+ }
+
private fun simpleSubCategory(vararg shortcuts: Shortcut) =
ShortcutSubCategory(simpleGroupLabel, shortcuts.asList())
@@ -196,6 +279,37 @@ class ShortcutHelperCategoriesRepositoryTest : SysuiTestCase() {
commands = listOf(ShortcutCommand(keys.map { ShortcutKey.Text(it) })),
)
+ private fun simpleDrawableModifierShortcut(
+ vararg keys: String,
+ modifierDrawable: Drawable,
+ ): Shortcut {
+ val keyShortcuts = keys.map { ShortcutKey.Text(it) }
+ return Shortcut(
+ label = simpleShortcutLabel,
+ commands =
+ listOf(
+ ShortcutCommand(
+ listOf(ShortcutKey.Icon.DrawableIcon(drawable = modifierDrawable)) +
+ keyShortcuts
+ )
+ ),
+ )
+ }
+
+ private fun simpleResIdModifierShortcut(vararg keys: String, modifierResId: Int): Shortcut {
+ val keyShortcuts = keys.map { ShortcutKey.Text(it) }
+ return Shortcut(
+ label = simpleShortcutLabel,
+ commands =
+ listOf(
+ ShortcutCommand(
+ listOf(ShortcutKey.Icon.ResIdIcon(drawableResId = modifierResId)) +
+ keyShortcuts
+ )
+ ),
+ )
+ }
+
private fun simpleGroup(vararg shortcuts: KeyboardShortcutInfo) =
KeyboardShortcutGroup(simpleGroupLabel, shortcuts.asList())
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/CommandQueueInitializerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/CommandQueueInitializerTest.kt
index 2a196c6b979f..1b3f29a6f0c5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/CommandQueueInitializerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/CommandQueueInitializerTest.kt
@@ -32,7 +32,7 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.verify
-@EnableFlags(StatusBarSimpleFragment.FLAG_NAME)
+@EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
@SmallTest
@RunWith(AndroidJUnit4::class)
class CommandQueueInitializerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationScrimNestedScrollConnectionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationScrimNestedScrollConnectionTest.kt
index 75479ad35725..60b95ad632e1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationScrimNestedScrollConnectionTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationScrimNestedScrollConnectionTest.kt
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification
+import androidx.compose.foundation.gestures.FlingBehavior
+import androidx.compose.foundation.gestures.ScrollScope
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollSource.Companion.UserInput
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -35,6 +37,13 @@ class NotificationScrimNestedScrollConnectionTest : SysuiTestCase() {
private var scrimOffset = 0f
private var contentHeight = 0f
private var isCurrentGestureOverscroll = false
+ private val customFlingBehavior =
+ object : FlingBehavior {
+ override suspend fun ScrollScope.performFling(initialVelocity: Float): Float {
+ scrollBy(initialVelocity)
+ return initialVelocity / 2f
+ }
+ }
private val scrollConnection =
NotificationScrimNestedScrollConnection(
@@ -51,6 +60,7 @@ class NotificationScrimNestedScrollConnectionTest : SysuiTestCase() {
wasStarted = true
isStarted = false
},
+ flingBehavior = customFlingBehavior,
)
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
index c0057431f536..657e9df0029b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
@@ -58,6 +58,7 @@ import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.withArgCaptor
import com.android.systemui.util.time.SystemClock
import com.android.systemui.wmshell.BubblesManager
+import com.google.android.msdl.domain.MSDLPlayer
import java.util.Optional
import junit.framework.Assert
import org.junit.After
@@ -110,6 +111,7 @@ class ExpandableNotificationRowControllerTest : SysuiTestCase() {
private val dismissibilityProvider: NotificationDismissibilityProvider = mock()
private val statusBarService: IStatusBarService = mock()
private val uiEventLogger: UiEventLogger = mock()
+ private val msdlPlayer: MSDLPlayer = mock()
private lateinit var controller: ExpandableNotificationRowController
@Before
@@ -150,7 +152,8 @@ class ExpandableNotificationRowControllerTest : SysuiTestCase() {
dragController,
dismissibilityProvider,
statusBarService,
- uiEventLogger
+ uiEventLogger,
+ msdlPlayer,
)
whenever(view.childrenContainer).thenReturn(childrenContainer)
@@ -268,14 +271,14 @@ class ExpandableNotificationRowControllerTest : SysuiTestCase() {
controller.mSettingsListener.onSettingChanged(
BUBBLES_SETTING_URI,
view.entry.sbn.userId,
- "1"
+ "1",
)
verify(childView).setBubblesEnabledForUser(true)
controller.mSettingsListener.onSettingChanged(
BUBBLES_SETTING_URI,
view.entry.sbn.userId,
- "9"
+ "9",
)
verify(childView).setBubblesEnabledForUser(false)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index b2794d8f9b56..0eb620343e6a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -804,6 +804,13 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
}
@Test
+ public void onBackPressedResetsLeaveOnKeyguardHide() {
+ when(mPrimaryBouncerInteractor.isFullyShowing()).thenReturn(true);
+ mStatusBarKeyguardViewManager.onBackPressed();
+ verify(mStatusBarStateController).setLeaveOpenOnKeyguardHide(false);
+ }
+
+ @Test
public void testResetHideBouncerWhenShowingIsFalse_alternateBouncerHides() {
// GIVEN the keyguard is showing
reset(mAlternateBouncerInteractor);
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 9ec61063691a..c091cbf6c062 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Neem jou skerm op?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Neem een app op"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Neem hele skerm op"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Wanneer jy jou hele skerm opneem, word enigiets wat op jou skerm wys, opgeneem. Wees dus versigtig met dinge soos wagwoorde, betalingbesonderhede, boodskappe, foto’s, en oudio en video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Wanneer jy ’n app opneem, word enigiets wat in daardie app gewys of gespeel word, opgeneem. Wees dus versigtig met dinge soos wagwoorde, betalingbesonderhede, boodskappe, foto’s, en oudio en video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Neem skerm op"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Soekkortpaaie"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Geen soekresultate nie"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Vou ikoon in"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Vou ikoon uit"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"of"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Sleephandvatsel"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 598e224c6a0e..af2971b2ec81 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"ማያ ገፅዎን ይቀዳሉ?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"አንድ መተግበሪያ ቅዳ"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"መላው ማያ ገፅን ቅረጽ"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"መላው ማያ ገፅዎን በሚቀዱበት ጊዜ፣ በማያ ገፅዎ ላይ የሚታየው ማንኛውም ነገር ይቀዳል። ስለዚህ እንደ የይለፍ ቃላት፣ የክፍያ ዝርዝሮች፣ መልዕክቶች፣ ፎቶዎች እና ኦዲዮ እና ቪድዮ ላሉ ነገሮች ጥንቃቄ ያድርጉ።"</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"መተግበሪያን ሲቀዱ በዚያ መተግበሪያ ውስጥ የሚታይ ወይም የሚጫወት ማንኛውም ነገር ይቀዳል። ስለዚህ እንደ የይለፍ ቃላት፣ የክፍያ ዝርዝሮች፣ መልዕክቶች፣ ፎቶዎች እና ኦዲዮ እና ቪድዮ ላሉ ነገሮች ጥንቃቄ ያድርጉ።"</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"ማያ ገፅን ቅረጽ"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"መዘርጊያ አዶ"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ወይም"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"መያዣ ይጎትቱ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 342c8c2980d9..4ebac5a86ec1 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"هل تريد تسجيل محتوى الشاشة؟"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"تسجيل محتوى تطبيق واحد"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"تسجيل محتوى الشاشة بالكامل"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"أثناء تسجيل محتوى الشاشة بالكامل، يتم تسجيل كل المحتوى المعروض على شاشتك. لذا يُرجى توخي الحذر بشأن المعلومات، مثل كلمات المرور وتفاصيل الدفع والرسائل والصور وملفات الصوت والفيديو."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"أثناء تسجيل محتوى تطبيق، يتم تسجيل أي محتوى يتم عرضه أو تشغيله في ذلك التطبيق. لذا يُرجى توخي الحذر بشأن المعلومات، مثل كلمات المرور وتفاصيل الدفع والرسائل والصور وملفات الصوت والفيديو."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"تسجيل محتوى الشاشة"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"رمز التوسيع"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"أو"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"مقبض السحب"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index b71db2e8528c..85517f3865d2 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"আপোনাৰ স্ক্ৰীনখন ৰেকৰ্ড কৰিবনে?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"এটা এপ্ ৰেকৰ্ড কৰক"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"গোটেই স্ক্ৰীনখন ৰেকৰ্ড কৰক"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"আপুনি গোটেই স্ক্ৰীনখন ৰেকৰ্ডিং কৰিলে, আপোনাৰ স্ক্ৰীনখনত দেখুওৱা যিকোনো বস্তু ৰেকৰ্ড কৰা হয়। গতিকে, পাছৱৰ্ড, পৰিশোধৰ সবিশেষ, বাৰ্তা, ফট’ আৰু অডিঅ’ আৰু ভিডিঅ’ৰ ক্ষেত্ৰত সাৱধান হওক।"</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"আপুনি কোনো এপ্ ৰেকৰ্ড কৰিলে, সেই এপত দেখুওৱা বা প্লে’ কৰা যিকোনো বস্তু ৰেকৰ্ড কৰা হয়। গতিকে, পাছৱৰ্ড, পৰিশোধৰ সবিশেষ, বাৰ্তা, ফট’ আৰু অডিঅ’ আৰু ভিডিঅ’ৰ ক্ষেত্ৰত সাৱধান হওক।"</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"স্ক্ৰীনখন ৰেকৰ্ড কৰক"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"আটাইবোৰ মচক"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"পৰিচালনা কৰক"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ইতিহাস"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"জাননীৰ ছেটিং"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"জাননীৰ ইতিহাস"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"নতুন"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"নীৰৱ"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"জাননীসমূহ"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"বিস্তাৰ কৰাৰ চিহ্ন"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"অথবা"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ড্ৰেগ হেণ্ডেল"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index d51c9aa3af3d..f08724a81449 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Ekran qeydə alınsın?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Bir tətbiqi qeydə alın"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Bütün ekranı qeydə alın"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Bütün ekranı qeydə alarkən ekranda göstərilən bütün kontent qeydə alınır. Parol, ödəniş detalları, mesaj, foto, habelə audio və video kimi məlumatlarla bağlı diqqətli olun."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Tətbiq qeydə aldıqda həmin tətbiqdə göstərilən və ya işə salınan bütün kontent qeydə alınır. Parol, ödəniş detalları, mesaj, foto, habelə audio və video kimi məlumatlarla bağlı diqqətli olun."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Ekranı qeydə alın"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Axtarış qısayolları"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Axtarış nəticəsi yoxdur"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"İkonanı yığcamlaşdırın"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"İkonanı genişləndirin"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"və ya"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Dəstəyi çəkin"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 881495f0d3fe..f5096915e261 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Želite da snimite ekran?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Snimi jednu aplikaciju"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Snimi ceo ekran"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Kada snimate ceo ekran, snima se sve što je na njemu. Zato pazite na lozinke, informacije o plaćanju, poruke, slike, audio i video sadržaj."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Kada snimate aplikaciju, snima se sav sadržaj koji se prikazuje ili pušta u njoj. Zato pazite na lozinke, informacije o plaćanju, poruke, slike, audio i video sadržaj."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Snimi ekran"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Obriši sve"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Upravljaj"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Istorija"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"Podešavanja obaveštenja"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"Istorija obaveštenja"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"Novo"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"Nečujno"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Obaveštenja"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečice pretrage"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nema rezultata pretrage"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za skupljanje"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za proširivanje"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ili"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Marker za prevlačenje"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 16bb70cf62ca..bc0e2d189c02 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Запісаць экран?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Запісаць адну праграму"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Запісаць змесціва ўсяго экрана"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Пры запісе ўсяго экрана запісваецца ўсё, што паказваецца на экране. Таму прадухіліце паказ пароляў, плацежных рэквізітаў, паведамленняў, фота, відэа і аўдыя."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Пры запісе праграмы запісваецца ўсё, што паказваецца або прайграецца ў гэтай праграме. Таму прадухіліце паказ пароляў, плацежных рэквізітаў, паведамленняў, фота, відэа і аўдыя."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Запісаць экран"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок \"Разгарнуць\""</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"або"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Маркер перацягвання"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 2b3a0b9383bf..2ee1f5f0f21e 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Да се записва ли екранът?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Записване на едно приложение"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Записване на целия екран"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Когато записвате целия си екран, се записва всичко, което се показва на него. Затова бъдете внимателни с неща като пароли, подробности за начини на плащане, съобщения, снимки, аудио и видео."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Когато записвате приложение, се записва всичко, което се показва или възпроизвежда в него. Затова бъдете внимателни с неща като пароли, подробности за начини на плащане, съобщения, снимки, аудио и видео."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Записване на екрана"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за разгъване"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Манипулатор за преместване с плъзгане"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index f39a644d5e88..c593210c4613 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"আপনার স্ক্রিন রেকর্ড করবেন?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"একটি অ্যাপ রেকর্ড করুন"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"সম্পূর্ণ স্ক্রিন রেকর্ড করুন"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"আপনার সম্পূর্ণ স্ক্রিন রেকর্ড করার সময়, আপনার স্ক্রিনে দেখানো সব কিছু রেকর্ড করা হয়। তাই পাসওয়ার্ড, পেমেন্টের বিবরণ, মেসেজ, ফটো এবং অডিও ও ভিডিওর মতো বিষয়ের ক্ষেত্রে সতর্ক থাকুন।"</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"আপনি কোনও অ্যাপ রেকর্ড করার সময়, সেই অ্যাপে দেখানো বা চালানো সব কিছু রেকর্ড করা হয়। তাই পাসওয়ার্ড, পেমেন্টের বিবরণ, মেসেজ, ফটো এবং অডিও ও ভিডিওর মতো বিষয়ের ক্ষেত্রে সতর্ক থাকুন।"</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"স্ক্রিন রেকর্ড করুন"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"সব মুছে দিন"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"ম্যানেজ করুন"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ইতিহাস"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"বিজ্ঞপ্তি সেটিংস"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"বিজ্ঞপ্তির ইতিহাস"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"নতুন"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"আওয়াজ করবে না"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"বিজ্ঞপ্তি"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"আইকন বড় করুন"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"অথবা"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"টেনে আনার হ্যান্ডেল"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index ec57c6abede1..38f42659245e 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Snimati ekran?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Snimaj jednu aplikaciju"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Snimaj cijeli ekran"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Kada snimate cijeli ekran, snimat će se sve što se prikazuje na ekranu. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, zvukovi i videozapisi."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Kada snimate aplikaciju, snimat će se sve što se prikazuje ili reproducira u toj aplikaciji. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, zvukovi i videozapisi."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Snimaj ekran"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Obriši sve"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Upravljajte"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historija"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"Postavke obavještenja"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"Historija obavještenja"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"Novo"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"Nečujno"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Obavještenja"</string>
@@ -1413,9 +1413,15 @@
<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 tastature"</string>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečica pretraživanja"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nema rezultata pretraživanja"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona sužavanja"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona proširivanja"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ili"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Ručica za prevlačenje"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 9c9ba90a225d..bcaca5ae16e9 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Vols gravar la pantalla?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Grava una aplicació"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Grava tota la pantalla"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Quan graves tota la pantalla, es grava tot el que es mostra en pantalla. Per aquest motiu, ves amb compte amb elements com les contrasenyes, les dades de pagament, els missatges, les fotos, i l\'àudio i el vídeo."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Quan graves una aplicació, es grava tot el que es mostra o es reprodueix en aquesta aplicació. Per aquest motiu, ves amb compte amb les contrasenyes, les dades de pagament, els missatges, les fotos, i l\'àudio i el vídeo."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Grava la pantalla"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Dreceres de cerca"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"No hi ha cap resultat de la cerca"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Replega la icona"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Desplega la icona"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Ansa per arrossegar"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 95f369988c1e..76ae86deddd4 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Pořídit nahrávku obrazovky?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Nahrát jednu aplikaci"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Nahrát celou obrazovku"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Při nahrávání celé obrazovky se zaznamenává veškerý obsah na obrazovce. Buďte proto opatrní, když jde o hesla, platební údaje, zprávy, fotografie, zvuk a video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Při nahrávání aplikace se zaznamenává všechno, co se v dané obrazovce zobrazuje nebo přehrává. Buďte proto opatrní, když jde o hesla, platební údaje, zprávy, fotografie, zvuk a video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Nahrát obrazovku"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Vyhledat zkratky"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Žádné výsledky hledání"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona sbalení"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozbalení"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"nebo"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Úchyt pro přetažení"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 8266799a081d..abcd4b8d45ce 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Vil du optage din skærm?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Optag én app"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Optag hele skærmen"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Når du optager hele skærmen, bliver alt det, der vises på skærmen, optaget. Vær derfor forsigtig med ting såsom adgangskoder, betalingsoplysninger, beskeder, billeder, lyd og video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Når du optager en app, optages alt det, der vises eller afspilles i den pågældende app. Vær derfor forsigtig med ting såsom adgangskoder, betalingsoplysninger, beskeder, billeder, lyd og video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Optag skærm"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Ryd alle"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Administrer"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historik"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"Indstillinger for notifikationer"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"Notifikationshistorik"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"Nye"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"Lydløs"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifikationer"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Genveje til søgning"</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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikon for Udvid"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eller"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Håndtag"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index a4bc364be58b..9799a932bcd9 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Bildschirm aufnehmen?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Einzelne App aufnehmen"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Gesamten Bildschirm aufnehmen"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Wenn du den gesamten Bildschirm aufnimmst, ist in der Aufnahme alles zu sehen, was auf dem Bildschirm angezeigt wird. Sei also vorsichtig mit Informationen wie Passwörtern, Zahlungsdetails, Nachrichten, Fotos sowie Audio- und Videoinhalten."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Wenn du eine App aufnimmst, ist in der Aufnahme alles zu sehen, was in dieser App angezeigt oder abgespielt wird. Sei also vorsichtig mit Informationen wie Passwörtern, Zahlungsdetails, Nachrichten, Fotos sowie Audio- und Videoinhalten."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Bildschirm aufnehmen"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Tastenkürzel suchen"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Keine Suchergebnisse"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Symbol „Minimieren“"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Symbol „Maximieren“"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"oder"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Ziehpunkt"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 278a8ea7cfeb..7200a91b618e 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Να γίνει εγγραφή της οθόνης σας;"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Εγγραφή μίας εφαρμογής"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Εγγραφή ολόκληρης της οθόνης"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Όταν κάνετε εγγραφή ολόκληρης της οθόνη σας, καταγράφεται οτιδήποτε εμφανίζεται σε αυτήν. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα, τις φωτογραφίες, τον ήχο και το βίντεο."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Όταν κάνετε εγγραφή μιας εφαρμογής, καταγράφεται οτιδήποτε εμφανίζεται ή αναπαράγεται στη συγκεκριμένη εφαρμογή. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα, τις φωτογραφίες, τον ήχο και το βίντεο."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Εγγραφή οθόνης"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Εικονίδιο ανάπτυξης"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ή"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Λαβή μεταφοράς"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 2fbd60a11faf..1ecf4f17cac3 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Record your screen?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Record one app"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Record entire screen"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"When you\'re recording your entire screen, anything displayed on your screen is recorded. So, be careful with things like passwords, payment details, messages, photos, audio and video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"When you\'re recording an app, anything displayed or played in that app is recorded. So, be careful with things like passwords, payment details, messages, photos, audio and video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Record screen"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"No search results"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Drag handle"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 23475fab120c..f775513ca418 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Record your screen?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Record one app"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Record entire screen"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"When you’re recording your entire screen, anything shown on your screen is recorded. So be careful with things like passwords, payment details, messages, photos, and audio and video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"When you’re recording an app, anything shown or played in that app is recorded. So be careful with things like passwords, payment details, messages, photos, and audio and video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Record screen"</string>
@@ -136,17 +138,14 @@
<string name="screenrecord_stop_dialog_message_specific_app" msgid="5995770227684523244">"You\'re currently recording <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="screenrecord_stop_dialog_button" msgid="2883812564938194350">"Stop recording"</string>
<string name="share_to_app_chip_accessibility_label" msgid="4210256229976947065">"Sharing screen"</string>
- <!-- no translation found for share_to_app_chip_accessibility_label_generic (5517431657924536133) -->
- <skip />
+ <string name="share_to_app_chip_accessibility_label_generic" msgid="5517431657924536133">"Sharing content"</string>
<string name="share_to_app_stop_dialog_title" msgid="9212915050910250438">"Stop sharing screen?"</string>
- <!-- no translation found for share_to_app_stop_dialog_title_generic (9079161538135843648) -->
- <skip />
+ <string name="share_to_app_stop_dialog_title_generic" msgid="9079161538135843648">"Stop sharing?"</string>
<string name="share_to_app_stop_dialog_message_entire_screen_with_host_app" msgid="522823522115375414">"You\'re currently sharing your entire screen with <xliff:g id="HOST_APP_NAME">%1$s</xliff:g>"</string>
<string name="share_to_app_stop_dialog_message_entire_screen" msgid="5090115386271179270">"You\'re currently sharing your entire screen with an app"</string>
<string name="share_to_app_stop_dialog_message_single_app_specific" msgid="5923772039347985172">"You\'re currently sharing <xliff:g id="APP_BEING_SHARED_NAME">%1$s</xliff:g>"</string>
<string name="share_to_app_stop_dialog_message_single_app_generic" msgid="6681016774654578261">"You\'re currently sharing an app"</string>
- <!-- no translation found for share_to_app_stop_dialog_message_generic (7622174291691249392) -->
- <skip />
+ <string name="share_to_app_stop_dialog_message_generic" msgid="7622174291691249392">"You\'re currently sharing with an app"</string>
<string name="share_to_app_stop_dialog_button" msgid="6334056916284230217">"Stop sharing"</string>
<string name="cast_screen_to_other_device_chip_accessibility_label" msgid="4687917476203009885">"Casting screen"</string>
<string name="cast_to_other_device_stop_dialog_title" msgid="7836517190930357326">"Stop casting?"</string>
@@ -521,10 +520,8 @@
<string name="communal_widget_picker_title" msgid="1953369090475731663">"Lock screen widgets"</string>
<string name="communal_widget_picker_description" msgid="490515450110487871">"Anyone can view widgets on your lock screen, even if your tablet\'s locked."</string>
<string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"unselect widget"</string>
- <!-- no translation found for accessibility_action_label_shrink_widget (8259511040536438771) -->
- <skip />
- <!-- no translation found for accessibility_action_label_expand_widget (9190524260912211759) -->
- <skip />
+ <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Decrease height"</string>
+ <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Increase height"</string>
<string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Lock screen widgets"</string>
<string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"To open an app using a widget, you’ll need to verify it’s you. Also, keep in mind that anyone can view them, even when your tablet’s locked. Some widgets may not have been intended for your lock screen and may be unsafe to add here."</string>
<string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Got it"</string>
@@ -1411,9 +1408,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"No search results"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Drag handle"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 2fbd60a11faf..1ecf4f17cac3 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Record your screen?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Record one app"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Record entire screen"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"When you\'re recording your entire screen, anything displayed on your screen is recorded. So, be careful with things like passwords, payment details, messages, photos, audio and video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"When you\'re recording an app, anything displayed or played in that app is recorded. So, be careful with things like passwords, payment details, messages, photos, audio and video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Record screen"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"No search results"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Drag handle"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 2fbd60a11faf..1ecf4f17cac3 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Record your screen?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Record one app"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Record entire screen"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"When you\'re recording your entire screen, anything displayed on your screen is recorded. So, be careful with things like passwords, payment details, messages, photos, audio and video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"When you\'re recording an app, anything displayed or played in that app is recorded. So, be careful with things like passwords, payment details, messages, photos, audio and video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Record screen"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"No search results"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Drag handle"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 9ea154020d73..77c2a639f903 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"¿Quieres grabar la pantalla?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Grabar una app"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Grabar toda la pantalla"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Cuando grabes toda la pantalla, se grabará todo lo que se muestre en ella. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes, fotos, audios y videos."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Cuando grabes una app, se registrará todo lo que se muestre o reproduzca en ella. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes, fotos, audios y videos."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Grabar pantalla"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Cerrar todo"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Administrar"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"Configuración de notificaciones"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"Historial de notificaciones"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"Nuevo"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"Silenciadas"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificaciones"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Buscar combinaciones de teclas"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"La búsqueda no arrojó resultados"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícono de contraer"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícono de expandir"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Controlador de arrastre"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 16ffd44a044c..81b1562ed533 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"¿Grabar la pantalla?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Grabar una aplicación"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Grabar toda la pantalla"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Cuando grabas toda la pantalla, se graba todo lo que se muestre en ella. Debes tener cuidado con elementos como contraseñas, detalles de pagos, mensajes, fotos, audio y vídeo."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Cuando grabas una aplicación, se graba todo lo que se muestre o reproduzca en ella. Debes tener cuidado con elementos como contraseñas, detalles de pagos, mensajes, fotos, audio y vídeo."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Grabar pantalla"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atajos de búsqueda"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"No hay resultados de búsqueda"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icono de contraer"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icono de desplegar"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Controlador de arrastre"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 5c9664b84d66..56039da5acc8 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Kas salvestada ekraanikuvast video?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Ühe rakenduse salvestamine"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Kogu ekraanikuva salvestamine"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Kui salvestate kogu ekraani, salvestatakse kõik ekraanil kuvatud andmed. Seega olge ettevaatlik selliste andmetega nagu paroolid, makseteave, sõnumid, fotod ning heli ja video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Kui salvestate rakendust, salvestatakse kõik, mida selles rakenduses näidatakse või esitatakse. Seega olge ettevaatlik selliste andmetega nagu paroolid, makseteave, sõnumid, fotod ning heli ja video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Ekraanikuva jäädvustamine"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Otsingu otseteed"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Otsingutulemused puuduvad"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ahendamisikoon"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Laiendamisikoon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"või"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Lohistamispide"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 31348b61484f..426d1d754c94 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Pantaila grabatu nahi duzu?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Grabatu aplikazio bat"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Grabatu pantaila osoa"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Pantaila osoa grabatzen ari zarenean, pantailan agertzen den guztia grabatzen da. Beraz, kontuz ibili pasahitzekin, ordainketen xehetasunekin, mezuekin, argazkiekin, audioekin eta bideoekin, besteak beste."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Aplikazio bat grabatzen ari zarenean, aplikazio horretan agertzen den edo bertan erreproduzitzen ari den guztia grabatzen da. Beraz, kontuz ibili pasahitzekin, ordainketen xehetasunekin, mezuekin, argazkiekin, audioekin eta bideoekin, besteak beste."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Grabatu pantaila"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Bilatu lasterbideak"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ez dago bilaketa-emaitzarik"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Tolesteko ikonoa"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Zabaltzeko ikonoa"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"edo"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Arrastatzeko kontrol-puntua"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index bc89200599cb..b0d23aa81898 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"صفحه‌نمایش ضبط شود؟"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"ضبط یک برنامه"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"ضبط کل صفحه‌نمایش"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"وقتی کل صفحه‌نمایش را ضبط می‌کنید، هر چیزی که در صفحه‌نمایش نشان داده شود ضبط خواهد شد. درنتیجه مراقب چیزهایی مثل گذرواژه‌ها، جزئیات پرداخت، پیام‌ها، عکس‌ها، و صدا و تصویر باشید."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"وقتی برنامه‌ای را ضبط می‌کنید، هر چیزی که در آن برنامه نشان داده شود یا پخش شود ضبط خواهد شد. درنتیجه مراقب چیزهایی مثل گذرواژه‌ها، جزئیات پرداخت، پیام‌ها، عکس‌ها، و صدا و تصویر باشید."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"ضبط صفحه‌نمایش"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"پاک کردن همه موارد"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"مدیریت"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"سابقه"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"تنظیمات اعلان"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"سابقه اعلان"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"جدید"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"بی‌صدا"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"اعلان‌ها"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"نماد ازهم بازکردن"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"یا"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"دستگیره کشاندن"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index a40cbaecfaa5..690228f9d333 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Tallennetaanko näytön toimintaa?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Tallenna yhdestä sovelluksesta"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Tallenna koko näyttö"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Kun tallennat koko näyttöä, kaikki näytöllä näkyvä sisältö tallennetaan. Ole siis varovainen, kun lisäät salasanoja, maksutietoja, viestejä, kuvia, audiota tai videoita."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Kun tallennat sovellusta, kaikki sovelluksessa näkyvä tai toistettu sisältö tallennetaan. Ole siis varovainen, kun lisäät salasanoja, maksutietoja, viestejä, kuvia, audiota tai videoita."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Tallenna näyttö"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pikahaut"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ei hakutuloksia"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Tiivistyskuvake"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Laajennuskuvake"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"tai"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Vetokahva"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 288be348f670..5ea58ce1e574 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Enregistrer votre écran?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Enregistrer une appli"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Enregistrer l\'écran entier"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Lorsque vous enregistrez l\'intégralité de votre écran, tout ce qui s\'affiche sur votre écran est enregistré. Par conséquent, soyez prudent avec les mots de passe, les détails du mode de paiement, les messages, les photos et les contenus audio et vidéo."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Lorsque vous enregistrez une appli, tout ce qui est affiché ou lu dans cette appli est enregistré. Par conséquent, soyez prudent avec les mots de passe, les détails du mode de paiement, les messages, les photos et les contenus audio et vidéo."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Enregistrer l\'écran"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Recherchez des raccourcis"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Aucun résultat de recherche"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icône Réduire"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icône Développer"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Poignée de déplacement"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 9d9f3f99708c..2be31b11c1f5 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Enregistrer l\'écran ?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Enregistrer une appli"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Enregistrer tout l\'écran"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Lorsque vous enregistrez l\'intégralité de votre écran, tout ce qui s\'y affiche est enregistré. Faites donc attention aux éléments tels que les mots de passe, les détails du mode de paiement, les messages, les photos, et les contenus audio et vidéo."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Lorsque vous enregistrez une appli, tout ce qui est affiché ou lu dans celle-ci est enregistré. Faites donc attention aux éléments tels que les mots de passe, détails de mode de paiement, messages, photos et contenus audio et vidéo."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Enregistrer l\'écran"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Raccourcis de recherche"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Aucun résultat de recherche"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icône Réduire"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icône Développer"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Poignée de déplacement"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 1430bc2a1131..2bd0b30988e7 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Queres gravar a túa pantalla?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Gravar unha aplicación"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Gravar pantalla completa"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Cando gravas a pantalla completa, recóllese todo o que se mostra nela. Recomendámosche que teñas coidado con determinada información, como os contrasinais, os detalles de pago, as mensaxes e as fotos, así como co contido de audio e de vídeo."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Cando gravas unha aplicación, recóllese todo o que se mostra ou reproduce nela. Recomendámosche que teñas coidado con determinada información, como os contrasinais, os detalles de pago, as mensaxes e as fotos, así como co contido de audio e de vídeo."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Gravar pantalla"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atallos de busca"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Non hai resultados de busca"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icona de contraer"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icona de despregar"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Controlador de arrastre"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index bc2739f3a9dc..becca8f8b37f 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"તમારી સ્ક્રીન રેકોર્ડ કરીએ?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"એક ઍપ રેકોર્ડ કરો"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"પૂર્ણ સ્ક્રીન રેકોર્ડ કરો"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"જ્યારે તમે તમારી પૂર્ણ સ્ક્રીન રેકોર્ડ કરી રહ્યાં હો, ત્યારે તમારી સ્ક્રીન પર બતાવવામાં આવતી હોય તેવી બધી વસ્તુ રેકોર્ડ કરવામાં આવે છે. તેથી પાસવર્ડ, ચુકવણીની વિગતો, મેસેજ, ફોટા અને ડિવાઇસ પર વાગી રહેલા ઑડિયો તથા વીડિયો જેવી બાબતોને લઈને સાવચેત રહો."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"જ્યારે તમે કોઈ ઍપને રેકોર્ડ કરી રહ્યાં હો, ત્યારે એ ઍપમાં બતાવવામાં કે ચલાવવામાં આવતી હોય તેવી બધી વસ્તુ રેકોર્ડ કરવામાં આવે છે. તેથી પાસવર્ડ, ચુકવણીની વિગતો, મેસેજ, ફોટા અને ડિવાઇસ પર વાગી રહેલા ઑડિયો તથા વીડિયો જેવી બાબતોને લઈને સાવચેત રહો."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"સ્ક્રીન રેકોર્ડ કરો"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"બધુ સાફ કરો"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"મેનેજ કરો"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ઇતિહાસ"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"નોટિફિકેશનના સેટિંગ"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"નોટિફિકેશનનો ઇતિહાસ"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"નવા"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"સાઇલન્ટ"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"નોટિફિકેશન"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"\'મોટું કરો\'નું આઇકન"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"અથવા"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ઑબ્જેક્ટ ખેંચવાનું હૅન્ડલ"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index f9a1fa5f84ad..a6fc05e2c7e0 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"क्या आपको स्क्रीन रिकॉर्ड करनी है?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"एक ऐप्लिकेशन की रिकॉर्डिंग करें"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"पूरी स्क्रीन रिकॉर्ड करें"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"पूरी स्क्रीन रिकॉर्ड करते समय, स्क्रीन पर दिखने वाली हर चीज़ रिकॉर्ड की जाती है. इसलिए पासवर्ड, पेमेंट के तरीके की जानकारी, मैसेज, डिवाइस पर चल रहे ऑडियो और वीडियो, और फ़ोटो जैसी चीज़ों को लेकर सावधानी बरतें."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"किसी ऐप्लिकेशन को रिकॉर्ड करने के दौरान, उस पर दिख रहा कॉन्टेंट या चल रहा मीडिया दूसरी स्क्रीन पर भी रिकॉर्ड होता है. इसलिए, रिकॉर्ड करते समय पासवर्ड, पेमेंट के तरीके की जानकारी, मैसेज, फ़ोटो, ऑडियो, और वीडियो को लेकर सावधानी बरतें."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"स्क्रीन रिकॉर्ड करें"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"बड़ा करने का आइकॉन"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"या"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"खींचकर छोड़ने वाला हैंडल"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 4a17fdc37b8e..cb7a1931be4d 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Želite li snimati zaslon?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Snimanje jedne aplikacije"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Snimanje cijelog zaslona"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Kad snimate cijeli zaslon, snima se sve što se prikazuje na zaslonu. Stoga pazite na stvari kao što su zaporke, podaci o plaćanju, poruke, fotografije te audio i videozapisi."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Kad snimate aplikaciju, snima se sve što se prikazuje ili reproducira u toj aplikaciji. Stoga pazite na stvari kao što su zaporke, podaci o plaćanju, poruke, fotografije te audio i videozapisi."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Snimanje zaslona"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečaci za pretraživanje"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nema rezultata pretraživanja"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za sažimanje"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za proširivanje"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ili"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Marker za povlačenje"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index ff5339ff5488..b09947fc2600 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Rögzíti a képernyőt?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Egyetlen alkalmazás rögzítése"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Teljes képernyő rögzítése"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"A teljes képernyő rögzítése esetén a képernyőn megjelenő minden tartalom rögzítésre kerül. Ezért legyen elővigyázatos a jelszavakkal, a fizetési adatokkal, az üzenetekkel, a fotókkal, valamint a hang- és videófelvételekkel."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Alkalmazás rögzítésekor az adott alkalmazásban megjelenített vagy lejátszott minden tartalom rögzítésre kerül. Ezért legyen elővigyázatos a jelszavakkal, a fizetési adatokkal, az üzenetekkel, a fotókkal, valamint a hang- és videófelvételekkel."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Képernyő rögzítése"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Billentyűparancsok keresése"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nincsenek keresési találatok"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Összecsukás ikon"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Kibontás ikon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"vagy"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Fogópont"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 8fb13478da16..174b52622fd2 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Տեսագրե՞լ ձեր էկրանը"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Տեսագրել մեկ հավելված"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Տեսագրել ամբողջ էկրանը"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Երբ դուք տեսագրում եք ամբողջ էկրանը, էկրանին ցուցադրվող ամեն ինչ տեսագրվում է։ Ուստի ուշադիր եղեք այնպիսի բաների հետ, ինչպիսիք են գաղտնաբառերը, վճարային տվյալները, հաղորդագրությունները, լուսանկարները, աուդիո և վիդեո բովանդակությունը։"</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Երբ դուք որևէ հավելված եք տեսագրում, հավելվածում ցուցադրվող կամ նվագարկվող ամեն ինչ տեսագրվում է։ Ուստի ուշադիր եղեք այնպիսի բաների հետ, ինչպիսիք են գաղտնաբառերը, վճարային տվյալները, հաղորդագրությունները, լուսանկարները, աուդիո և վիդեո բովանդակությունը։"</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Տեսագրել էկրանը"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ծավալել պատկերակը"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"կամ"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Տեղափոխման նշիչ"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 0b316befc259..e706b272458a 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Rekam layar Anda?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Rekam satu aplikasi"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Rekam seluruh layar"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Saat Anda merekam seluruh layar, semua hal yang ditampilkan di layar akan direkam. Jadi, berhati-hatilah saat memasukkan sandi, detail pembayaran, pesan, foto, audio, dan video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Jika Anda merekam aplikasi, semua hal yang ditampilkan atau diputar di aplikasi tersebut akan direkam. Jadi, berhati-hatilah saat memasukkan sandi, detail pembayaran, pesan, foto, audio, dan video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Rekam layar"</string>
@@ -409,7 +411,7 @@
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode satu tangan"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Alat bantu dengar"</string>
<string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktif"</string>
- <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Terputus"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Tidak terhubung"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Alat bantu dengar"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Sambungkan perangkat baru"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik untuk menyambungkan perangkat baru"</string>
@@ -1190,7 +1192,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grup"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 perangkat dipilih"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> perangkat dipilih"</string>
- <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(terputus)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(tidak terhubung)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Tidak dapat beralih. Ketuk untuk mencoba lagi."</string>
<string name="media_output_dialog_pairing_new" msgid="5098212763195577270">"Hubungkan perangkat"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Buka aplikasi untuk mentransmisikan sesi ini."</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pintasan penelusuran"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Tidak ada hasil penelusuran"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikon ciutkan"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikon luaskan"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"atau"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Handel geser"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 700ae589073c..267291069366 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Viltu taka upp skjáinn?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Taka upp eitt forrit"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Taka upp allan skjáinn"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Þegar þú tekur upp allan skjáinn verður allt sem er sýnilegt á skjánum tekið upp. Passaðu því upp á aðgangsorð, greiðsluupplýsingar, skilaboð, myndir, hljóð og vídeó."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Þegar þú tekur upp forrit verður allt sem er sýnilegt eða spilað í forritinu tekið upp. Passaðu því upp á aðgangsorð, greiðsluupplýsingar, skilaboð, myndir, hljóð og vídeó."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Taka upp skjá"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Hreinsa allt"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Stjórna"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Ferill"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"Tilkynningastillingar"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"Tilkynningaferill"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"Nýtt"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"Hljóðlaust"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Tilkynningar"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Leitarflýtileiðir"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Engar leitarniðurstöður"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Minnka tákn"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Stækka tákn"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eða"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Dragkló"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index e7734fa4a38d..fd56c5b69f5a 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Registrare lo schermo?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Registra un\'app"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Registra l\'intero schermo"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Quando registri l\'intero schermo, tutto ciò che viene mostrato sullo schermo viene registrato. Presta quindi attenzione a password, dati di pagamento, messaggi, foto, audio e video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Quando registri un\'app, tutto ciò che viene mostrato o riprodotto al suo interno viene registrato. Presta quindi attenzione a password, dati di pagamento, messaggi, foto, audio e video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Registra lo schermo"</string>
@@ -136,17 +138,14 @@
<string name="screenrecord_stop_dialog_message_specific_app" msgid="5995770227684523244">"Al momento stai registrando <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="screenrecord_stop_dialog_button" msgid="2883812564938194350">"Interrompi registrazione"</string>
<string name="share_to_app_chip_accessibility_label" msgid="4210256229976947065">"Condivisione dello schermo in corso"</string>
- <!-- no translation found for share_to_app_chip_accessibility_label_generic (5517431657924536133) -->
- <skip />
+ <string name="share_to_app_chip_accessibility_label_generic" msgid="5517431657924536133">"Condivisione di contenuti in corso…"</string>
<string name="share_to_app_stop_dialog_title" msgid="9212915050910250438">"Vuoi interrompere la condivisione dello schermo?"</string>
- <!-- no translation found for share_to_app_stop_dialog_title_generic (9079161538135843648) -->
- <skip />
+ <string name="share_to_app_stop_dialog_title_generic" msgid="9079161538135843648">"Interrompere la condivisione?"</string>
<string name="share_to_app_stop_dialog_message_entire_screen_with_host_app" msgid="522823522115375414">"Al momento stai condividendo l\'intero schermo con <xliff:g id="HOST_APP_NAME">%1$s</xliff:g>"</string>
<string name="share_to_app_stop_dialog_message_entire_screen" msgid="5090115386271179270">"Al momento stai condividendo l\'intero schermo con un\'app"</string>
<string name="share_to_app_stop_dialog_message_single_app_specific" msgid="5923772039347985172">"Al momento stai condividendo <xliff:g id="APP_BEING_SHARED_NAME">%1$s</xliff:g>"</string>
<string name="share_to_app_stop_dialog_message_single_app_generic" msgid="6681016774654578261">"Al momento stai condividendo un\'app"</string>
- <!-- no translation found for share_to_app_stop_dialog_message_generic (7622174291691249392) -->
- <skip />
+ <string name="share_to_app_stop_dialog_message_generic" msgid="7622174291691249392">"Al momento stai condividendo contenuti con un\'app"</string>
<string name="share_to_app_stop_dialog_button" msgid="6334056916284230217">"Interrompi condivisione"</string>
<string name="cast_screen_to_other_device_chip_accessibility_label" msgid="4687917476203009885">"Trasmissione dello schermo in corso…"</string>
<string name="cast_to_other_device_stop_dialog_title" msgid="7836517190930357326">"Vuoi interrompere la trasmissione?"</string>
@@ -521,10 +520,8 @@
<string name="communal_widget_picker_title" msgid="1953369090475731663">"Widget della schermata di blocco"</string>
<string name="communal_widget_picker_description" msgid="490515450110487871">"Chiunque può visualizzare i widget sulla tua schermata di blocco, anche se il tablet è bloccato."</string>
<string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"deseleziona widget"</string>
- <!-- no translation found for accessibility_action_label_shrink_widget (8259511040536438771) -->
- <skip />
- <!-- no translation found for accessibility_action_label_expand_widget (9190524260912211759) -->
- <skip />
+ <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Riduci altezza"</string>
+ <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Aumenta altezza"</string>
<string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widget della schermata di blocco"</string>
<string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Per aprire un\'app utilizzando un widget, dovrai verificare la tua identità. Inoltre tieni presente che chiunque può vederlo, anche quando il tablet è bloccato. Alcuni widget potrebbero non essere stati progettati per la schermata di blocco e potrebbe non essere sicuro aggiungerli qui."</string>
<string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Ok"</string>
@@ -1413,9 +1410,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Scorciatoie per la ricerca"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nessun risultato di ricerca"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icona Comprimi"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icona Espandi"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"oppure"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Punto di trascinamento"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 553eaae83da9..384c680b116f 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"להקליט את המסך?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"הקלטה של אפליקציה אחת"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"הקלטה של כל המסך"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"כשמקליטים את כל המסך, כל מה שמופיע במסך מוקלט. מומלץ להיזהר עם סיסמאות, פרטי תשלום, הודעות, תמונות, אודיו וסרטונים."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"כשמקליטים אפליקציה, כל מה שרואים או מפעילים בה מוקלט. מומלץ להיזהר עם סיסמאות, פרטי תשלום, הודעות, תמונות, אודיו וסרטונים."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"הקלטת המסך"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"ניקוי הכול"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"ניהול"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"היסטוריה"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"הגדרות של התראות"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"היסטוריית ההתראות"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"התראות חדשות"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"מצב שקט"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"התראות"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"סמל ההרחבה"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"או"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"נקודת האחיזה לגרירה"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index a6fffee06695..a0a3b2bdd403 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"画面を録画しますか?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"1 つのアプリを録画"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"画面全体を録画"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"画面全体を録画すると、画面に表示されるものがすべて録画されます。パスワード、お支払いの詳細、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"アプリを録画すると、そのアプリで表示または再生される内容がすべて録画されます。パスワード、お支払いの詳細、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"画面を録画"</string>
@@ -1411,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"開くアイコン"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"または"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ドラッグ ハンドル"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 9608253c1e1e..471957e044cb 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"გსურთ თქვენი ეკრანის ჩაწერა?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"ერთი აპის ჩაწერა"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"მთლიანი ეკრანის ჩაწერა"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"მთლიანი ეკრანის ჩაწერისას ჩაიწერება ყველაფერი, რაც თქვენს ეკრანზე გამოჩნდება. ამიტომ სიფრთხილე გამოიჩინეთ ისეთ ინფორმაციასთან, როგორიცაა პაროლები, გადახდის დეტალები, შეტყობინებები, ფოტოები, აუდიო და ვიდეო."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"აპის ჩაწერისას ჩაიწერება ყველაფერი, რაც ამ აპში გამოჩნდება ან დაიკვრება. ამიტომ სიფრთხილე გამოიჩინეთ ისეთ ინფორმაციასთან, როგორიცაა პაროლები, გადახდის დეტალები, შეტყობინებები, ფოტოები, აუდიო და ვიდეო."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"ეკრანის ჩაწერა"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ხატულის გაფართოება"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ან"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"სახელური ჩავლებისთვის"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 0456fa8164fc..3dbfd86b3f38 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Қолданба экранын жазасыз ба?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Бір қолданба экранын жазу"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Бүкіл экранды жазу"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Бүкіл экранды жазған кезде, онда көрінетін барлық нәрсе жазылады. Сондықтан құпия сөздерді, төлем туралы мәліметті, хабарларды немесе басқа құпия ақпаратты енгізген кезде сақ болыңыз."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Қолданбаны жазған кезде, онда көрінетін не ойнатылатын барлық нәрсе жазылады. Сондықтан құпия сөздерді, төлем туралы мәліметті, хабарларды немесе басқа құпия ақпаратты енгізген кезде сақ болыңыз."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Экранды жазу"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Жаю белгішесі"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"немесе"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Сүйрейтін тетік"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 3c33531717bc..b2c8977ab7ce 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"ថត​អេក្រង់​របស់អ្នកឬ?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"ថត​កម្មវិធី​ទោល"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"ថតអេក្រង់ទាំងមូល"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"នៅពេល​អ្នកកំពុង​ថតអេក្រង់​ទាំងមូល​របស់អ្នក អ្វីគ្រប់យ៉ាង​ដែលបង្ហាញ​នៅលើ​អេក្រង់​របស់អ្នក​ត្រូវបាន​ថត។ ដូច្នេះ សូមប្រុងប្រយ័ត្នចំពោះអ្វីៗដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ សារ រូបថត ព្រមទាំងសំឡេង និងវីដេអូ។"</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"នៅពេលអ្នក​កំពុង​ថតកម្មវិធី​ណាមួយ អ្វីគ្រប់យ៉ាង​ដែលបង្ហាញ ឬចាក់​នៅក្នុង​កម្មវិធីនោះ​ត្រូវបាន​ថត។ ដូច្នេះ សូមប្រុងប្រយ័ត្នចំពោះអ្វីៗដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ សារ រូបថត ព្រមទាំងសំឡេង និងវីដេអូ។"</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"ថត​អេក្រង់"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"រូបតំណាង \"ពង្រីក\""</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ឬ"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ដង​អូស"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index dca2e4b4a59e..20c367696858 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್‌ ಅನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಬೇಕೇ?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"ಒಂದು ಆ್ಯಪ್ ಅನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"ಸಂಪೂರ್ಣ ಸ್ಕ್ರೀನ್ ಅನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"ನಿಮ್ಮ ಸಂಪೂರ್ಣ ಸ್ಕ್ರೀನ್‌ ಅನ್ನು ನೀವು ರೆಕಾರ್ಡ್ ಮಾಡುತ್ತಿರುವಾಗ, ನಿಮ್ಮ ಸ್ಕ್ರೀನ್‌ ಮೇಲೆ ಗೋಚರಿಸುವ ಎಲ್ಲವನ್ನೂ ರೆಕಾರ್ಡ್ ಮಾಡಲಾಗುತ್ತದೆ. ಆದ್ದರಿಂದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳು, ಪಾವತಿ ವಿವರಗಳು, ಸಂದೇಶಗಳು, ಫೋಟೋಗಳು ಮತ್ತು ಆಡಿಯೋ ಮತ್ತು ವೀಡಿಯೊದಂತಹ ವಿಷಯಗಳ ಬಗ್ಗೆ ಜಾಗರೂಕರಾಗಿರಿ."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"ನೀವು ಆ್ಯಪ್ ಅನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡುವಾಗ, ಆ ಆ್ಯಪ್‌ನಲ್ಲಿ ತೋರಿಸಿರುವ ಅಥವಾ ಪ್ಲೇ ಮಾಡಿದ ಎಲ್ಲವನ್ನೂ ರೆಕಾರ್ಡ್ ಮಾಡಲಾಗುತ್ತದೆ. ಆದ್ದರಿಂದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳು, ಪಾವತಿ ವಿವರಗಳು, ಸಂದೇಶಗಳು, ಫೋಟೋಗಳು ಮತ್ತು ಆಡಿಯೋ ಮತ್ತು ವೀಡಿಯೊದಂತಹ ವಿಷಯಗಳ ಬಗ್ಗೆ ಜಾಗರೂಕರಾಗಿರಿ."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿ"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"ನಿರ್ವಹಿಸಿ"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ಇತಿಹಾಸ"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"ನೋಟಿಫಿಕೇಶನ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"ನೋಟಿಫಿಕೇಶನ್ ಇತಿಹಾಸ"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"ಹೊಸತು"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"ನಿಶ್ಶಬ್ದ"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"ಅಧಿಸೂಚನೆಗಳು"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ವಿಸ್ತೃತಗೊಳಿಸುವ ಐಕಾನ್"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ಅಥವಾ"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ಡ್ರ್ಯಾಗ್‌ ಹ್ಯಾಂಡಲ್‌"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 8674dc3ad863..35dc245643ae 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"화면을 녹화하시겠습니까?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"단일 앱 녹화"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"전체 화면 녹화"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"전체 화면을 녹화하면 화면에 표시되는 모든 항목이 녹화됩니다. 따라서 비밀번호, 결제 세부정보, 메시지, 사진, 오디오 및 동영상 등이 노출되지 않도록 주의하세요."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"앱을 녹화하면 앱에 표시되거나 앱에서 재생되는 모든 항목이 녹화됩니다. 따라서 비밀번호, 결제 세부정보, 메시지, 사진, 오디오 및 동영상 등이 노출되지 않도록 주의하세요."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"화면 녹화"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"모두 지우기"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"관리"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"기록"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"알림 설정"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"알림 기록"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"새 알림"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"무음"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"알림"</string>
@@ -1413,15 +1413,21 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"확장 아이콘"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"또는"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"드래그 핸들"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"키보드 설정"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"키보드를 사용하여 이동"</string>
- <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"단축키 알아보기"</string>
+ <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"단축키에 관해 알아보세요."</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"터치패드를 사용하여 이동"</string>
<string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"터치패드 동작 알아보기"</string>
<string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"키보드와 터치패드를 사용하여 이동"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 363342a94793..72e86cc4a703 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Экранды жаздырасызбы?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Бир колдонмону жаздыруу"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Бүтүндөй экранды жаздыруу"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Бүтүндөй экранды жаздырганда, андагы нерселердин баары видеого түшүп калат. Андыктан этият болуп, сырсөздөр, төлөм ыкмалары, билдирүүлөр, сүрөттөр, аудио жана видео материалдар сыяктуу купуя нерселерди көрсөтүп албаңыз."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Колдонмону жаздырганда ал колдонмодо көрсөтүлүп же ойнотулуп жаткан нерселер жаздырылат. Андыктан сырсөздөрдү, төлөмдүн чоо-жайын, билдирүүлөрдү, сүрөттөрдү, аудио жана видеону көрсөтүп албаңыз."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Экранды жаздыруу"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Жайып көрсөтүү сүрөтчөсү"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"же"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Cүйрөө маркери"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 54c2c6baf6a7..f6fe3cce059a 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"ບັນທຶກໜ້າຈໍຂອງທ່ານບໍ?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"ບັນທຶກແອັບດຽວ"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"ບັນທຶກໝົດໜ້າຈໍ"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"ເມື່ອທ່ານບັນທຶກໝົດໜ້າຈໍຂອງທ່ານ, ລະບົບຈະບັນທຶກທຸກສິ່ງທີ່ສະແດງຢູ່ໜ້າຈໍຂອງທ່ານ. ດັ່ງນັ້ນ, ໃຫ້ລະມັດລະວັງສິ່ງຕ່າງໆ ເຊັ່ນ: ລະຫັດຜ່ານ, ລາຍລະອຽດການຈ່າຍເງິນ, ຂໍ້ຄວາມ, ຮູບພາບ, ພ້ອມທັງສຽງ ແລະ ວິດີໂອ."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"ເມື່ອທ່ານບັນທຶກແອັບ, ລະບົບຈະບັນທຶກທຸກສິ່ງທີ່ສະແດງ ຫຼື ຫຼິ້ນຢູ່ໃນແອັບນັ້ນ. ດັ່ງນັ້ນ, ໃຫ້ລະມັດລະວັງສິ່ງຕ່າງໆ ເຊັ່ນ: ລະຫັດຜ່ານ, ລາຍລະອຽດການຈ່າຍເງິນ, ຂໍ້ຄວາມ, ຮູບພາບ, ພ້ອມທັງສຽງ ແລະ ວິດີໂອ."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"ບັນທຶກໜ້າຈໍ"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ໄອຄອນຂະຫຍາຍ"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ຫຼື"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ບ່ອນຈັບລາກ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index dca26a41edbf..70a0063d7627 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Įrašyti ekraną?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Įrašyti vieną programą"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Įrašyti visą ekraną"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Kai įrašote visą ekraną, įrašomas visas ekrane rodomas turinys. Todėl būkite atsargūs naudodami slaptažodžius, išsamią mokėjimo metodo informaciją, pranešimus, nuotraukas ir garso bei vaizdo įrašus."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Kai įrašote programą, įrašomas visas toje programoje rodomas ar leidžiamas turinys. Todėl būkite atsargūs naudodami slaptažodžius, išsamią mokėjimo metodo informaciją, pranešimus, nuotraukas ir garso bei vaizdo įrašus."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Įrašyti ekraną"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Paieškos šaukiniai"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nėra jokių paieškos rezultatų"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Sutraukimo piktograma"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Išskleidimo piktograma"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"arba"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Vilkimo rankenėlė"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index c5ba0ad80493..360afad1c6fa 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Vai ierakstīt ekrānu?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Ierakstīt vienu lietotni"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Ierakstīt visu ekrānu"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Ierakstot visu ekrānu, viss, kas redzams ekrānā, tiek ierakstīts. Tāpēc piesardzīgi apejieties ar parolēm, maksājumu informāciju, ziņojumiem, fotoattēliem un audio un video saturu."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Ierakstot lietotni, tiek ierakstīts viss attiecīgajā lietotnē rādītais vai atskaņotais. Tāpēc piesardzīgi apejieties ar parolēm, maksājumu informāciju, ziņojumiem, fotoattēliem un audio un video saturu."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Ierakstīt ekrānu"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Meklēšanas saīsnes"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nav meklēšanas rezultātu"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Sakļaušanas ikona"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Izvēršanas ikona"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"vai"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Vilkšanas turis"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 65e958e8d765..ebd62a9568e0 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Да се снима екранот?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Снимање на една апликација"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Снимање на целиот екран"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Додека го снимате целиот екран, сѐ што е прикажано на екранот се снима. Затоа, бидете внимателни со лозинките, деталите за плаќање, пораките, фотографиите и аудиото и видеото."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Додека снимате апликација, може да се сними сѐ што се прикажува или пушта во таа апликација. Затоа, бидете внимателни со лозинките, деталите за плаќање, пораките, фотографиите и аудиото и видеото."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Снимај го екранот"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Избриши сѐ"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Управувајте"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Историја"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"Поставки за известувања"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"Историја на известувања"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"Нов"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"Безгласно"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Известувања"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за проширување"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Рачка за влечење"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index e10ecff4b318..6152fce2e02b 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"നിങ്ങളുടെ സ്ക്രീൻ റെക്കോർഡ് ചെയ്യണോ?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"ഒരു ആപ്പ് റെക്കോർഡ് ചെയ്യുക"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"സ്ക്രീൻ പൂർണ്ണമായി റെക്കോർഡ് ചെയ്യുക"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"നിങ്ങളുടെ സ്ക്രീൻ പൂർണ്ണമായി റെക്കോർഡ് ചെയ്യുമ്പോൾ, സ്ക്രീനിൽ ദൃശ്യമാകുന്ന എല്ലാം റെക്കോർഡ് ചെയ്യപ്പെടും. അതിനാൽ പാസ്‍വേഡുകൾ, പേയ്‌മെന്റ് വിശദാംശങ്ങൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ, ഓഡിയോ, വീഡിയോ എന്നിവ പോലുള്ള കാര്യങ്ങൾ നൽകുമ്പോൾ സൂക്ഷിക്കുക."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"നിങ്ങളുടെ ആപ്പ് റെക്കോർഡ് ചെയ്യുമ്പോൾ, ആ ആപ്പിൽ കാണിക്കുന്നതോ പ്ലേ ചെയ്യുന്നതോ ആയ എല്ലാ കാര്യങ്ങളും റെക്കോർഡ് ചെയ്യപ്പെടും. അതിനാൽ പാസ്‍വേഡുകൾ, പേയ്‌മെന്റ് വിശദാംശങ്ങൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ, ഓഡിയോ, വീഡിയോ എന്നിവ പോലുള്ള കാര്യങ്ങൾ നൽകുമ്പോൾ സൂക്ഷിക്കുക."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"സ്ക്രീൻ റെക്കോർഡ് ചെയ്യുക"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"എല്ലാം മായ്‌ക്കുക"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"മാനേജ് ചെയ്യുക"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ചരിത്രം"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"അറിയിപ്പ് ക്രമീകരണം"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"അറിയിപ്പ് ചരിത്രം"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"പുതിയത്"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"നിശബ്‌ദം"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"അറിയിപ്പുകൾ"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"വികസിപ്പിക്കൽ ഐക്കൺ"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"അല്ലെങ്കിൽ"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"വലിച്ചിടുന്നതിനുള്ള ഹാൻഡിൽ"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index cb5f054cccf5..aafc8c610c55 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Дэлгэцээ бичих үү?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Нэг аппыг бичих"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Бүтэн дэлгэцийг бичих"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Таныг бүтэн дэлгэцээ бичиж байхад дэлгэц дээр тань харуулж буй аливаа зүйлийг бичдэг. Тиймээс нууц үг, төлбөрийн дэлгэрэнгүй, мессеж, зураг, аудио, видео зэрэг зүйлд болгоомжтой хандаарай."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Таныг апп бичиж байхад тухайн аппад харуулж эсвэл тоглуулж буй аливаа зүйлийг бичдэг. Тиймээс нууц үг, төлбөрийн дэлгэрэнгүй, мессеж, зураг, аудио, видео зэрэг зүйлд болгоомжтой хандаарай."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Дэлгэцийг бичих"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Бүгдийг арилгах"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Удирдах"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Түүх"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"Мэдэгдлийн тохиргоо"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"Мэдэгдлийн түүх"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"Шинэ"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"Чимээгүй"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Мэдэгдлүүд"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Дэлгэх дүрс тэмдэг"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"эсвэл"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Чирэх бариул"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 8aa0afaaa207..fbbb1670b286 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"तुमची स्क्रीन रेकॉर्ड करायची आहे का?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"एक अ‍ॅप रेकॉर्ड करा"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"पूर्ण स्क्रीन रेकॉर्ड करा"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"तुम्ही तुमची पूर्ण स्क्रीन रेकॉर्ड करता, तेव्हा तुमच्या स्क्रीनवर दाखवलेली कोणतीही गोष्टी रेकॉर्ड केली जाते. त्यामुळे पासवर्ड, पेमेंट तपशील, मेसेज, फोटो आणि ऑडिओ व व्हिडिओ यांसारख्या गोष्टींबाबत सावधगिरी बाळगा."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"तुम्ही अ‍ॅप रेकॉर्ड करता, तेव्हा त्या अ‍ॅपमध्ये दाखवलेली किंवा प्ले केलेली कोणतीही गोष्ट रेकॉर्ड केली जाते. त्यामुळे पासवर्ड, पेमेंट तपशील, मेसेज, फोटो आणि ऑडिओ व व्हिडिओ यांसारख्या गोष्टींबाबत सावधगिरी बाळगा."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"स्क्रीन रेकॉर्ड करा"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"सर्व साफ करा"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"व्यवस्थापित करा"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"इतिहास"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"नोटिफिकेशन सेटिंग्ज"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"नोटिफिकेशन इतिहास"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"नवीन"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"सायलंट"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"सूचना"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"विस्तार करा आयकन"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"किंवा"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ड्रॅग हॅंडल"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index d0071f4d73d7..087c8a664076 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Rakam skrin anda?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Rakam satu apl"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Rakam seluruh skrin"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Apabila anda merakam seluruh skrin anda, apa-apa sahaja yang dipaparkan pada skrin anda akan dirakam. Oleh hal yang demikian, berhati-hati dengan perkara seperti kata laluan, butiran pembayaran, mesej, foto dan audio serta video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Apabila anda merakam apl, apa-apa sahaja yang dipaparkan atau dimainkan dalam apl tersebut akan dirakam. Oleh hal yang demikian, berhati-hati dengan perkara seperti kata laluan, butiran pembayaran, mesej, foto dan audio serta video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Rakam skrin"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pintasan carian"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Tiada hasil carian"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Kuncupkan ikon"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Kembangkan ikon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"atau"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Pemegang seret"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index fd4c1478f914..d456bcae7085 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"ဖန်သားပြင်ကို ရိုက်ကူးမလား။"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"အက်ပ်တစ်ခုကို ရိုက်ကူးရန်"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"ဖန်သားပြင်တစ်ခုလုံးကို ရိုက်ကူးရန်"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"သင့်ဖန်သားပြင်တစ်ခုလုံး ရိုက်ကူးနေချိန်တွင် ဖန်သားပြင်တွင် ပြထားသည့် အရာအားလုံးကို ရိုက်ကူးသည်။ စကားဝှက်၊ ငွေပေးချေမှု အချက်အလက်၊ မက်ဆေ့ဂျ်၊ ဓာတ်ပုံ၊ အသံနှင့် ဗီဒီယိုကဲ့သို့ အရာများကို ဂရုစိုက်ပါ။"</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"အက်ပ်ကို ရိုက်ကူးနေချိန်တွင် ယင်းအက်ပ်တွင် ပြထားသော (သို့) ဖွင့်ထားသော အရာအားလုံးကို ရိုက်ကူးသည်။ စကားဝှက်၊ ငွေပေးချေမှု အချက်အလက်၊ မက်ဆေ့ဂျ်၊ ဓာတ်ပုံ၊ အသံနှင့် ဗီဒီယိုကဲ့သို့ အရာများကို ဂရုစိုက်ပါ။"</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"ဖန်သားပြင်ကို ရိုက်ကူးရန်"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ပိုပြရန် သင်္ကေတ"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"သို့မဟုတ်"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ဖိဆွဲအထိန်း"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 1c30ca7a4f4c..1fbb35b0905e 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Vil du ta opp skjermen?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Ta opp én app"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Ta opp hele skjermen"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Når du tar opp hele skjermen, blir alt som vises på skjermen, tatt opp. Derfor bør du være forsiktig med for eksempel passord, betalingsopplysninger, meldinger, bilder, lyd og video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Når du tar opp en app, blir alt som vises eller spilles av i appen, tatt opp. Derfor bør du være forsiktig med for eksempel passord, betalingsopplysninger, meldinger, bilder, lyd og video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Ta opp skjermen"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Snarveier til søk"</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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Vis-ikon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eller"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Håndtak"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index f7ac880de720..381118ac4d6c 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"तपाईंको स्क्रिन रेकर्ड गर्ने हो?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"एउटा एप रेकर्ड गर्नुहोस्"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"पूरै स्क्रिन रेकर्ड गर्नुहोस्"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"तपाईंले आफ्नो पूरै स्क्रिन रेकर्ड गरिरहेका बेला तपाईंको स्क्रिनमा देखाइने सबै सामग्री रेकर्ड गरिन्छ। त्यसैले पासवर्ड, भुक्तानीसम्बन्धी विवरण, म्यासेज, फोटो र अडियो तथा भिडियो जस्ता कुरा हेर्दा वा प्ले गर्दा सावधानी अपनाउनुहोला।"</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"तपाईंले यो एप रेकर्ड गरिरहेका बेला यो एपमा देखाइने वा प्ले गरिने सबै सामग्री रेकर्ड गरिन्छ। त्यसैले पासवर्ड, भुक्तानीसम्बन्धी विवरण, म्यासेज, फोटो र अडियो तथा भिडियो जस्ता कुरा हेर्दा वा प्ले गर्दा सावधानी अपनाउनुहोला।"</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"स्क्रिन रेकर्ड गर्नुहोस्"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"\"एक्स्पान्ड गर्नुहोस्\" आइकन"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"वा"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ड्र्याग ह्यान्डल"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 4cea60528e2a..8ff59ee93c98 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Je scherm opnemen?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Eén app opnemen"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Hele scherm opnemen"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Als je je hele scherm opneemt, wordt alles opgenomen wat op je scherm wordt getoond. Wees daarom voorzichtig met bijvoorbeeld wachtwoorden, betalingsgegevens, berichten, foto\'s, en audio en video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Als je een app opneemt, wordt alles opgenomen wat wordt getoond of afgespeeld in die app. Wees daarom voorzichtig met bijvoorbeeld wachtwoorden, betalingsgegevens, berichten, foto\'s, en audio en video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Scherm opnemen"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Alles wissen"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Beheren"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Geschiedenis"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"Instellingen voor meldingen"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"Meldings­geschiedenis"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"Nieuw"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"Stil"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Meldingen"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Snelkoppelingen voor zoekopdrachten"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Geen zoekresultaten"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icoon voor samenvouwen"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icoon voor uitvouwen"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"of"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Handgreep voor slepen"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index bbbea612f7f8..60864409ee7f 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"ଆପଣଙ୍କ ସ୍କ୍ରିନକୁ ରେକର୍ଡ କରିବେ?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"ଗୋଟିଏ ଆପ ରେକର୍ଡ କରନ୍ତୁ"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"ସମ୍ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନ ରେକର୍ଡ କରନ୍ତୁ"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"ଆପଣ ଆପଣଙ୍କର ସମ୍ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନ ରେକର୍ଡ କରିବା ସମୟରେ, ଆପଣଙ୍କ ସ୍କ୍ରିନରେ ଦେଖାଯାଉଥିବା ସବୁକିଛି ରେକର୍ଡ ହୋଇଥାଏ। ତେଣୁ ପାସୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ମେସେଜ, ଫଟୋ ଏବଂ ଅଡିଓ ଓ ଭିଡିଓ ପରି ବିଷୟଗୁଡ଼ିକ ପ୍ରତି ସତର୍କ ରୁହନ୍ତୁ।"</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"ଆପଣ ଏକ ଆପ ରେକର୍ଡ କରିବା ସମୟରେ, ସେହି ଆପରେ ଦେଖାଯାଉଥିବା କିମ୍ବା ପ୍ଲେ ହେଉଥିବା ସବୁକିଛି ରେକର୍ଡ ହୋଇଥାଏ। ତେଣୁ ପାସୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ମେସେଜ, ଫଟୋ ଏବଂ ଅଡିଓ ଓ ଭିଡିଓ ପରି ବିଷୟଗୁଡ଼ିକ ପ୍ରତି ସତର୍କ ରୁହନ୍ତୁ।"</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"ସ୍କ୍ରିନ ରେକର୍ଡ କରନ୍ତୁ"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ଆଇକନକୁ ବିସ୍ତାର କରନ୍ତୁ"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"କିମ୍ବା"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ଡ୍ରାଗ ହେଣ୍ଡେଲ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 0170a71db268..b99986a5e955 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"ਕੀ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਨੂੰ ਰਿਕਾਰਡ ਕਰਨਾ ਹੈ?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"ਇੱਕ ਐਪ ਨੂੰ ਰਿਕਾਰਡ ਕਰੋ"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"ਪੂਰੀ ਸਕ੍ਰੀਨ ਨੂੰ ਰਿਕਾਰਡ ਕਰੋ"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"ਜਦੋਂ ਤੁਸੀਂ ਆਪਣੀ ਪੂਰੀ ਸਕ੍ਰੀਨ ਨੂੰ ਰਿਕਾਰਡ ਕਰ ਰਹੇ ਹੁੰਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਦਿਖਾਈ ਜਾ ਰਹੀ ਹਰ ਚੀਜ਼ ਨੂੰ ਰਿਕਾਰਡ ਕੀਤਾ ਜਾਂਦਾ ਹੈ। ਇਸ ਲਈ ਪਾਸਵਰਡਾਂ, ਭੁਗਤਾਨ ਵੇਰਵਿਆਂ, ਸੁਨੇਹਿਆਂ, ਫ਼ੋਟੋਆਂ ਅਤੇ ਨਾਲ ਹੀ ਆਡੀਓ ਅਤੇ ਵੀਡੀਓ ਵਰਗੀਆਂ ਚੀਜ਼ਾਂ ਵਾਸਤੇ ਸਾਵਧਾਨ ਰਹੋ।"</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"ਜਦੋਂ ਤੁਸੀਂ ਕਿਸੇ ਐਪ ਨੂੰ ਰਿਕਾਰਡ ਕਰ ਰਹੇ ਹੁੰਦੇ ਹੋ, ਤਾਂ ਉਸ ਐਪ ਵਿੱਚ ਦਿਖਾਈ ਜਾਂ ਚਲਾਈ ਜਾ ਰਹੀ ਹਰ ਚੀਜ਼ ਨੂੰ ਰਿਕਾਰਡ ਕੀਤਾ ਜਾਂਦਾ ਹੈ। ਇਸ ਲਈ ਪਾਸਵਰਡਾਂ, ਭੁਗਤਾਨ ਵੇਰਵਿਆਂ, ਸੁਨੇਹਿਆਂ, ਫ਼ੋਟੋਆਂ ਅਤੇ ਆਡੀਓ ਅਤੇ ਵੀਡੀਓ ਵਰਗੀਆਂ ਚੀਜ਼ਾਂ ਵਾਸਤੇ ਸਾਵਧਾਨ ਰਹੋ।"</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡ ਕਰੋ"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ਇਤਿਹਾਸ"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"ਸੂਚਨਾ ਸੈਟਿੰਗਾਂ"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"ਸੂਚਨਾ ਇਤਿਹਾਸ"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"ਨਵੀਆਂ"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"ਸ਼ਾਂਤ"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"ਸੂਚਨਾਵਾਂ"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ਪ੍ਰਤੀਕ ਦਾ ਵਿਸਤਾਰ ਕਰੋ"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ਜਾਂ"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ਘਸੀਟਣ ਵਾਲਾ ਹੈਂਡਲ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 33a743f625d3..88177ac56bb7 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Nagrywać ekran?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Nagrywaj jedną aplikację"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Nagrywaj cały ekran"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Kiedy nagrywasz cały ekran, nagrane zostanie wszystko, co jest na nim widoczne. Dlatego uważaj na hasła, dane do płatności, wiadomości, zdjęcia, nagrania audio czy filmy."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Kiedy nagrywasz aplikację, wszystko, co jest w niej wyświetlane lub odtwarzane, zostaje nagrane. Dlatego zachowaj ostrożność w zakresie haseł, danych do płatności, wiadomości, zdjęć, audio i filmów."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Nagrywaj ekran"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Skróty do wyszukiwania"</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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozwijania"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"lub"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Uchwyt do przeciągania"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 8041760ae14c..e67c16856e58 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Gravar a tela?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Gravar um app"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Gravar a tela toda"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Quando você grava a tela toda, tudo o que aparece nela é registrado. Portanto, tenha cuidado com senhas, detalhes de pagamento, mensagens, fotos, áudios e vídeos."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Quando você grava um app, todas as informações visíveis ou abertas nele ficam registradas. Portanto, tenha cuidado com senhas, detalhes de pagamento, mensagens, fotos, áudios e vídeos."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Gravar a tela"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atalhos de pesquisa"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nenhum resultado de pesquisa"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone \"Fechar\""</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone \"Abrir\""</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Alça de arrastar"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index f0009986b232..30e16f06f00f 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Gravar o ecrã?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Gravar uma app"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Gravar o ecrã inteiro"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Quando está a gravar o ecrã inteiro, tudo o que é apresentado no ecrã é gravado. Por isso, tenha cuidado com, por exemplo, palavras-passe, detalhes de pagamento, mensagens, fotos, áudio e vídeo."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Quando está a gravar uma app, tudo o que é apresentado ou reproduzido nessa app é gravado. Por isso, tenha cuidado com, por exemplo, palavras-passe, detalhes de pagamento, mensagens, fotos, áudio e vídeo."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Gravar ecrã"</string>
@@ -136,17 +138,14 @@
<string name="screenrecord_stop_dialog_message_specific_app" msgid="5995770227684523244">"Neste momento, está a gravar a app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="screenrecord_stop_dialog_button" msgid="2883812564938194350">"Parar gravação"</string>
<string name="share_to_app_chip_accessibility_label" msgid="4210256229976947065">"A partilhar o ecrã"</string>
- <!-- no translation found for share_to_app_chip_accessibility_label_generic (5517431657924536133) -->
- <skip />
+ <string name="share_to_app_chip_accessibility_label_generic" msgid="5517431657924536133">"A partilhar conteúdo"</string>
<string name="share_to_app_stop_dialog_title" msgid="9212915050910250438">"Parar a partilha do ecrã?"</string>
- <!-- no translation found for share_to_app_stop_dialog_title_generic (9079161538135843648) -->
- <skip />
+ <string name="share_to_app_stop_dialog_title_generic" msgid="9079161538135843648">"Parar a partilha?"</string>
<string name="share_to_app_stop_dialog_message_entire_screen_with_host_app" msgid="522823522115375414">"Neste momento, está a partilhar todo o seu ecrã com a app <xliff:g id="HOST_APP_NAME">%1$s</xliff:g>"</string>
<string name="share_to_app_stop_dialog_message_entire_screen" msgid="5090115386271179270">"Neste momento, está a partilhar todo o seu ecrã com uma app"</string>
<string name="share_to_app_stop_dialog_message_single_app_specific" msgid="5923772039347985172">"Neste momento, está a partilhar a app <xliff:g id="APP_BEING_SHARED_NAME">%1$s</xliff:g>"</string>
<string name="share_to_app_stop_dialog_message_single_app_generic" msgid="6681016774654578261">"Neste momento, está a partilhar uma app"</string>
- <!-- no translation found for share_to_app_stop_dialog_message_generic (7622174291691249392) -->
- <skip />
+ <string name="share_to_app_stop_dialog_message_generic" msgid="7622174291691249392">"Neste momento, está a partilhar com uma app"</string>
<string name="share_to_app_stop_dialog_button" msgid="6334056916284230217">"Parar partilha"</string>
<string name="cast_screen_to_other_device_chip_accessibility_label" msgid="4687917476203009885">"A transmitir o ecrã"</string>
<string name="cast_to_other_device_stop_dialog_title" msgid="7836517190930357326">"Parar a transmissão?"</string>
@@ -521,10 +520,8 @@
<string name="communal_widget_picker_title" msgid="1953369090475731663">"Widgets do ecrã de bloqueio"</string>
<string name="communal_widget_picker_description" msgid="490515450110487871">"Todos podem pode ver widgets no ecrã de bloqueio, mesmo com o tablet bloqueado."</string>
<string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"desmarcar widget"</string>
- <!-- no translation found for accessibility_action_label_shrink_widget (8259511040536438771) -->
- <skip />
- <!-- no translation found for accessibility_action_label_expand_widget (9190524260912211759) -->
- <skip />
+ <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Diminuir altura"</string>
+ <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Aumentar altura"</string>
<string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets do ecrã de bloqueio"</string>
<string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para abrir uma app através de um widget, vai ter de validar a sua identidade. Além disso, tenha em atenção que qualquer pessoa pode ver os widgets, mesmo quando o tablet estiver bloqueado. Alguns widgets podem não se destinar ao ecrã de bloqueio e pode ser inseguro adicioná-los aqui."</string>
<string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string>
@@ -1413,9 +1410,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atalhos de pesquisa"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nenhum resultado da pesquisa"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone de reduzir"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone de expandir"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Indicador para arrastar"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 8041760ae14c..e67c16856e58 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Gravar a tela?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Gravar um app"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Gravar a tela toda"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Quando você grava a tela toda, tudo o que aparece nela é registrado. Portanto, tenha cuidado com senhas, detalhes de pagamento, mensagens, fotos, áudios e vídeos."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Quando você grava um app, todas as informações visíveis ou abertas nele ficam registradas. Portanto, tenha cuidado com senhas, detalhes de pagamento, mensagens, fotos, áudios e vídeos."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Gravar a tela"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atalhos de pesquisa"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nenhum resultado de pesquisa"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone \"Fechar\""</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone \"Abrir\""</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Alça de arrastar"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 57a2a0c2da63..de7f8dac8dd1 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Înregistrezi ecranul?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Înregistrează o aplicație"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Înregistrează tot ecranul"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Când înregistrezi întregul ecran, se înregistrează tot ce apare pe ecran. Prin urmare, ai grijă cu parolele, detaliile de plată, mesajele, fotografiile și conținutul audio și video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Când înregistrezi o aplicație, se înregistrează tot ce se afișează sau se redă în aplicație. Prin urmare, ai grijă cu parolele, detaliile de plată, mesajele, fotografiile și conținutul audio și video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Înregistrează ecranul"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Comenzi directe de căutare"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Niciun rezultat al căutării"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Pictograma de restrângere"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Pictograma de extindere"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"sau"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Ghidaj de tragere"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 507f70926620..a007685d4af3 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Начать запись экрана?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Записывать одно приложение"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Записывать весь экран"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Во время записи всего экрана все данные и действия, которые на нем показываются, попадают на видео. Поэтому будьте осторожны с паролями, сведениями о способах оплаты, сообщениями, фотографиями, аудио- и видеозаписями."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Во время записи приложения все данные и действия, которые показываются в его окне, попадают на видео. Поэтому будьте осторожны с паролями, сведениями о способах оплаты, сообщениями, фотографиями, аудио- и видеозаписями."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Запись экрана"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Очистить все"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Настроить"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"История"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"Настройки уведомлений"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"История уведомлений"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"Новое"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"Без звука"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Уведомления"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок \"Развернуть\""</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Маркер перемещения"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index fb9be30202db..ae9c4d0cf711 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"ඔබේ තිරය පටිගත කරන්න ද?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"එක් යෙදුමක් පටිගත කරන්න"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"සම්පූර්ණ තිරය පටිගත කරන්න"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"ඔබ ඔබේ සම්පූර්ණ තිරය පටිගත කරන විට, ඔබේ තිරයේ පෙන්වන ඕනෑම දෙයක් වාර්තා වේ. ඒ නිසා මුරපද, ගෙවීම් විස්තර, පණිවුඩ, ඡායාරූප, සහ ශ්‍රව්‍ය සහ දෘශ්‍ය වැනි දේවල් පිළිබඳ ප්‍රවේශම් වන්න."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"ඔබ යෙදුමක් පටිගත කරන විට, එම යෙදුමේ පෙන්වන හෝ වාදනය කරන ඕනෑම දෙයක් වාර්තා වේ. ඒ නිසා මුරපද, ගෙවීම් විස්තර, පණිවුඩ, ඡායාරූප, සහ ශ්‍රව්‍ය සහ දෘශ්‍ය වැනි දේවල් පිළිබඳ ප්‍රවේශම් වන්න."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"තිරය පටිගත කරන්න"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"දිගහැරීම් නිරූපකය"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"හෝ"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"ඇදීම් හැඬලය"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 42a2613cf329..c2235667f08b 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Chcete nahrávať obrazovku?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Nahrávať jednu aplikáciu"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Nahrávať celú obrazovku"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Pri nahrávaní celej obrazovky sa zaznamená všetko, čo sa na nej zobrazuje. Preto venujte pozornosť položkám, ako sú heslá, platobné údaje, správy, fotky a zvuk či video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Pri nahrávaní aplikácie sa zaznamená všetko, čo sa v nej zobrazuje alebo prehráva. Preto venujte pozornosť položkám, ako sú heslá, platobné údaje, správy, fotky a zvuk či video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Nahrávať obrazovku"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Vymazať všetko"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Spravovať"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"História"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"Nastavenia upozornení"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"História upozornení"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"Nové"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"Tichý"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Upozornenia"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Vyhľadávacie odkazy"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Žiadne výsledky vyhľadávania"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona zbalenia"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozbalenia"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"alebo"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Presúvadlo"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 4ca7b244e9a7..15f1b3ccca7d 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Želite posneti zaslon?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Snemanje ene aplikacije"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Snemanje celotnega zaslona"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Pri snemanju celotnega zaslona se posname vse, kar je prikazano na zaslonu. Zato bodite previdni z gesli, podatki za plačilo, sporočili, fotografijami ter z zvokom in videom."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Pri snemanju aplikacije se posname vse, kar je prikazano ali predvajano v tej aplikaciji. Zato bodite previdni z gesli, podatki za plačilo, sporočili, fotografijami ter z zvokom in videom."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Snemanje zaslona"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Bližnjice za iskanje"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ni rezultatov iskanja"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za strnitev"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za razširitev"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ali"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Ročica za vlečenje"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index ddea921e900d..7f74487ac2b0 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Të regjistrohet ekrani?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Regjistro një aplikacion"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Regjistro të gjithë ekranin"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Kur regjistron të gjithë ekranin, regjistrohet çdo gjë e shfaqur në ekranin tënd. Prandaj, ki kujdes me gjërat si fjalëkalimet, detajet e pagesave, mesazhet, fotografitë, si dhe audion dhe videon."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Kur regjistron një aplikacion, regjistrohet çdo gjë që shfaqet ose luhet në atë aplikacion. Prandaj, ki kujdes me gjërat si fjalëkalimet, detajet e pagesave, mesazhet, fotografitë, si dhe audion dhe videon."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Regjistro ekranin"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Kërko për shkurtoret"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Asnjë rezultat kërkimi"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona e palosjes"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona e zgjerimit"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ose"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Doreza e zvarritjes"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 5936cd780e95..a1952d428f10 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Желите да снимите екран?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Сними једну апликацију"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Сними цео екран"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Када снимате цео екран, снима се све што је на њему. Зато пазите на лозинке, информације о плаћању, поруке, слике, аудио и видео садржај."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Када снимате апликацију, снима се сав садржај који се приказује или пушта у њој. Зато пазите на лозинке, информације о плаћању, поруке, слике, аудио и видео садржај."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Сними екран"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Обриши све"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Управљај"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Историја"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"Подешавања обавештења"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"Историја обавештења"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"Ново"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"Нечујно"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Обавештења"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за проширивање"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Маркер за превлачење"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 45e150a4574b..b898eafc7f03 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Vill du spela in det som visas på skärmen?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Spela in en app"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Spela in hela skärmen"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"När du spelar in hela skärmen spelas allt som visas på skärmen in. Var försiktig med sådant som lösenord, betalningsuppgifter, meddelanden, foton, ljud och video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"När du spelar in en app spelas allt som visas eller spelas upp i appen in. Var försiktig med sådant som lösenord, betalningsuppgifter, meddelanden, foton, ljud och video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Spela in skärmen"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Sökgenvägar"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Inga sökresultat"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikonen Komprimera"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikonen Utöka"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eller"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Handtag"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 86ea7e492007..8731337c88f0 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Ungependa kurekodi skrini yako?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Rekodi programu moja"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Rekodi skrini nzima"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Unaporekodi skrini yako nzima, chochote kinachoonyeshwa kwenye skrini yako kitarekodiwa. Kwa hivyo kuwa mwangalifu na vitu kama vile manenosiri, maelezo ya malipo, ujumbe, picha, sauti na video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Unaporekodi programu, chochote kinachoonyeshwa au kuchezwa kwenye programu hiyo kitarekodiwa. Kwa hivyo kuwa mwangalifu na vitu kama vile manenosiri, maelezo ya malipo, ujumbe, picha, sauti na video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Rekodi skrini"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Njia mkato za kutafutia"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Hamna matokeo ya utafutaji"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Kunja aikoni"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Panua aikoni"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"au"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Aikoni ya buruta"</string>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 4007bb1fcb98..393631e3364b 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -76,6 +76,14 @@
<dimen name="large_dialog_width">472dp</dimen>
<dimen name="large_screen_shade_header_height">42dp</dimen>
+
+ <!--
+ The horizontal distance between the shade overlay panel (both notifications and quick settings)
+ and the edge of the screen. On Compact screens in portrait orientation (< w600dp) this is
+ ignored in the shade layout, which takes up the full screen width without margins.
+ -->
+ <dimen name="shade_panel_margin_horizontal">24dp</dimen>
+
<!-- start padding is smaller to account for status icon margins coming from drawable itself -->
<dimen name="hover_system_icons_container_padding_start">3dp</dimen>
<dimen name="hover_system_icons_container_padding_end">4dp</dimen>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 93b18646a831..b75a2186ed64 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"உங்கள் திரையை ரெக்கார்டு செய்யவா?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"ஓர் ஆப்ஸை ரெக்கார்டு செய்தல்"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"முழுத் திரையை ரெக்கார்டு செய்தல்"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"முழுத் திரையை நீங்கள் ரெக்கார்டு செய்யும்போது அதில் காட்டப்படும் அனைத்தும் ரெக்கார்டு செய்யப்படும். எனவே கடவுச்சொற்கள், பேமெண்ட் விவரங்கள், மெசேஜ்கள், படங்கள், ஆடியோ, வீடியோ போன்றவை குறித்துக் கவனத்துடன் இருங்கள்."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"ஓர் ஆப்ஸை ரெக்கார்டு செய்யும்போது அதில் காட்டப்படும் அல்லது பிளே செய்யப்படும் அனைத்தும் ரெக்கார்டு செய்யப்படும். எனவே கடவுச்சொற்கள், பேமெண்ட் விவரங்கள், மெசேஜ்கள், படங்கள், ஆடியோ, வீடியோ போன்றவை குறித்துக் கவனத்துடன் இருங்கள்."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"திரையை ரெக்கார்டு செய்"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"விரிவாக்குவதற்கான ஐகான்"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"அல்லது"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"இழுப்பதற்கான ஹேண்டில்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 4a976513a8da..d66c6560fd7c 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"మీ స్క్రీన్‌ను రికార్డ్ చేయాలా?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"ఒక యాప్‌ను రికార్డ్ చేయండి"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"ఫుల్ స్క్రీన్‌ను రికార్డ్ చేయండి"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"మీ ఫుల్ స్క్రీన్‌ను మీరు రికార్డ్ చేసేటప్పుడు, మీ స్క్రీన్‌పై కనిపించేవన్నీ రికార్డ్ అవుతాయి. కాబట్టి పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, మెసేజ్‌లు, ఫోటోలు, ఆడియో, ఇంకా వీడియో వంటి విషయాల్లో జాగ్రత్త వహించండి."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"మీరు యాప్‌ను రికార్డ్ చేసేటప్పుడు, సంబంధిత యాప్‌లో కనిపించేవన్నీ లేదా ప్లే అయ్యేవన్నీ రికార్డ్ అవుతాయి. కాబట్టి పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, మెసేజ్‌లు, ఫోటోలు, ఆడియో, ఇంకా వీడియో వంటి విషయాల్లో జాగ్రత్త వహించండి."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"స్క్రీన్‌ను రికార్డ్ చేయండి"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"అన్నీ క్లియర్ చేయండి"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"మేనేజ్ చేయండి"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"హిస్టరీ"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"నోటిఫికేషన్ సెట్టింగ్‌లు"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"నోటిఫికేషన్ హిస్టరీ"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"కొత్తవి"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"నిశ్శబ్దం"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"నోటిఫికేషన్‌లు"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"విస్తరించండి చిహ్నం"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"లేదా"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"లాగే హ్యాండిల్"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index ac027c753d12..b7d1a32fdeba 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"บันทึกหน้าจอไหม"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"บันทึกแอปเดียว"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"บันทึกทั้งหน้าจอ"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"ขณะบันทึกทั้งหน้าจอ ระบบจะบันทึกทุกสิ่งที่แสดงอยู่บนหน้าจอ ดังนั้นโปรดระวังสิ่งต่างๆ อย่างเช่นรหัสผ่าน รายละเอียดการชำระเงิน ข้อความ รูปภาพ รวมถึงเสียงและวิดีโอ"</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"ขณะบันทึกแอป ระบบจะบันทึกทุกสิ่งที่แสดงหรือเล่นอยู่ในแอปดังกล่าว ดังนั้นโปรดระวังสิ่งต่างๆ อย่างเช่นรหัสผ่าน รายละเอียดการชำระเงิน ข้อความ รูปภาพ รวมถึงเสียงและวิดีโอ"</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"บันทึกหน้าจอ"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ไอคอนขยาย"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"หรือ"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"แฮนเดิลการลาก"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 09a0e0400310..a30a2f2f45f6 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"I-record ang iyong screen?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Mag-record ng isang app"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"I-record ang buong screen"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Kapag nire-record mo ang iyong buong screen, nire-record ang anumang ipinapakita sa screen mo. Kaya mag-ingat sa mga bagay-bagay tulad ng mga password, detalye ng pagbabayad, mensahe, larawan, at audio at video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Kapag nagre-record ka ng app, nire-record ang anumang ipinapakita o pine-play sa app na iyon. Kaya mag-ingat sa mga bagay-bagay tulad ng mga password, detalye ng pagbabayad, mensahe, larawan, at audio at video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"I-record ang screen"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Mga shortcut ng paghahanap"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Walang resulta ng paghahanap"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"I-collapse ang icon"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"I-expand ang icon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Handle sa pag-drag"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index ae9cd186520e..c79dfcf8f162 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Ekranınız kaydedilsin mi?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Bir uygulamayı kaydet"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Tüm ekranı kaydedin"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Tüm ekranınızı kaydettiğinizde ekranınızda gösterilen her şey kaydedilir. Bu nedenle şifre, ödeme ayrıntıları, mesaj, fotoğraf, ses ve video gibi öğeler konusunda dikkatli olun."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Bir uygulamayı kaydettiğinizde o uygulamada gösterilen veya oynatılan her şey kaydedilir. Bu nedenle şifre, ödeme ayrıntıları, mesaj, fotoğraf, ses ve video gibi öğeler konusunda dikkatli olun."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Ekranı kaydet"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Arama kısayolları"</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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Genişlet simgesi"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"veya"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Sürükleme tutamacı"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 820d072f152e..2808922e166c 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Записати відео з екрана?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Записувати один додаток"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Записувати весь екран"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Коли ви записуєте вміст усього екрана, на відео потрапляє все, що на ньому відображається. Тому будьте уважні з паролями, повідомленнями, фотографіями, аудіо, відео, платіжною інформацією тощо."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Коли ви записуєте додаток, на відео потрапляє все, що відображається або відтворюється в ньому. Тому будьте уважні з паролями, повідомленнями, фотографіями, аудіо, відео, платіжною інформацією тощо."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Записувати вміст екрана"</string>
@@ -1413,15 +1415,21 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок розгортання"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"або"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Маркер переміщення"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Налаштування клавіатури"</string>
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Навігація за допомогою клавіатури"</string>
- <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Комбінації клавіш: докладніше"</string>
+ <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Дізнайтеся більше про комбінації клавіш"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Навігація за допомогою сенсорної панелі"</string>
<string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Жести для сенсорної панелі: докладніше"</string>
<string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Навігація за допомогою клавіатури й сенсорної панелі"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index b98abbda3f7b..b72464cad145 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"آپ کی اسکرین ریکارڈ کریں؟"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"ایک ایپ ریکارڈ کریں"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"پوری اسکرین کو ریکارڈ کریں"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"جب آپ اپنی پوری اسکرین کو ریکارڈ کر رہے ہوتے ہیں تو آپ کی اسکرین پر دکھائی گئی ہر چیز ریکارڈ کی جاتی ہے۔ لہذا، پاس ورڈز، ادائیگی کی تفصیلات، پیغامات، تصاویر، ساتھ ہی آڈیو اور ویڈیو جیسی چیزوں کے سلسلے میں محتاط رہیں۔"</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"جب آپ کسی ایپ کو ریکارڈ کر رہے ہوتے ہیں تو اس ایپ میں دکھائی گئی یا چلائی گئی ہر چیز ریکارڈ کی جاتی ہے۔ لہذا، پاس ورڈز، ادائیگی کی تفصیلات، پیغامات، تصاویر، ساتھ ہی آڈیو اور ویڈیو جیسی چیزوں کے سلسلے میں محتاط رہیں۔"</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"اسکرین ریکارڈ کریں"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"آئیکن پھیلائیں"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"یا"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"گھسیٹنے کا ہینڈل"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 3309772d5fc8..7f6275c5a1d2 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Ekran yozib olinsinmi?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Bitta ilovani yozib olish"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Butun ekranni yozib olish"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Butun ekranni yozib olishda ekranda koʻrsatilgan barcha axborotlar yozib olinadi. Shu sababli parollar, toʻlov tafsilotlari, xabarlar, suratlar, audio va video chiqmasligi uchun ehtiyot boʻling."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Ilovani yozib olishda ilova koʻrsatilgan yoki ijro etilgan barcha axborotlar yozib olinadi. Shu sababli parollar, toʻlov tafsilotlari, xabarlar, suratlar, audio va video chiqmasligi uchun ehtiyot boʻling."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Ekranni yozib olish"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Tezkor tugmalar qidiruvi"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Hech narsa topilmadi"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Yigʻish belgisi"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Yoyish belgisi"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"yoki"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Surish dastagi"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index f404a2bf455b..388ebb804828 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Ghi màn hình?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Ghi một ứng dụng"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Ghi toàn màn hình"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Khi bạn ghi toàn màn hình, mọi nội dung trên màn hình của bạn đều được ghi. Vì vậy, hãy thận trọng để không làm lộ thông tin như mật khẩu, thông tin thanh toán, tin nhắn, ảnh, âm thanh và video."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Khi bạn ghi một ứng dụng, mọi nội dung xuất hiện hoặc phát trong ứng dụng đó sẽ đều được ghi. Vì vậy, hãy thận trọng để không làm lộ thông tin như mật khẩu, thông tin thanh toán, tin nhắn, ảnh, âm thanh và video."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Ghi màn hình"</string>
@@ -581,10 +583,8 @@
<string name="clear_all_notifications_text" msgid="348312370303046130">"Xóa tất cả"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Quản lý"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Lịch sử"</string>
- <!-- no translation found for notification_settings_button_description (2441994740884163889) -->
- <skip />
- <!-- no translation found for notification_history_button_description (1578657591405033383) -->
- <skip />
+ <string name="notification_settings_button_description" msgid="2441994740884163889">"Cài đặt thông báo"</string>
+ <string name="notification_history_button_description" msgid="1578657591405033383">"Nhật ký thông báo"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"Mới"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"Im lặng"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Thông báo"</string>
@@ -1413,9 +1413,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Lối tắt tìm kiếm"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Không có kết quả tìm kiếm nào"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Biểu tượng Thu gọn"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Biểu tượng Mở rộng"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"hoặc"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Nút kéo"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 24c9f40f05a7..b463900a331d 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"要录制屏幕吗?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"录制单个应用"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"录制整个屏幕"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"录制整个屏幕时,屏幕上显示的所有内容均会被录制。因此,请务必小心操作,谨防泄露密码、付款信息、消息、照片、音频、视频等。"</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"录制单个应用时,该应用中显示或播放的所有内容均会被录制。因此,请务必小心操作,谨防泄露密码、付款信息、消息、照片、音频、视频等。"</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"录制屏幕"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展开图标"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"或"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"拖动手柄"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index e7ebe5ccf697..91185912af9d 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"要錄影螢幕畫面嗎?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"錄影一個應用程式"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"錄影整個螢幕畫面"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"當你錄影整個螢幕畫面時,系統會錄影螢幕畫面上顯示的任何內容。因此,請謹慎處理密碼、付款資料、訊息、相片、音訊和影片等。"</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"當你錄影應用程式時,系統會錄影該應用程式中顯示或播放的任何內容。因此,請謹慎處理密碼、付款資料、訊息、相片、音訊和影片等。"</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"錄影螢幕畫面"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展開圖示"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"或"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"拖曳控點"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 0f298dc314c6..2189cbfdf278 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"要錄製畫面嗎?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"錄製單一應用程式"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"錄製整個畫面"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"錄製整個畫面時,系統會錄下畫面上的所有內容。因此,請謹慎處理密碼、付款資料、訊息、相片和影音內容等資訊。"</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"當你錄製應用程式畫面時,系統會錄下該應用程式顯示或播放的所有內容。因此,請謹慎處理密碼、付款資料、訊息、相片和影音內容等資訊。"</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"錄製畫面"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<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>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展開圖示"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"或"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"拖曳控點"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 444ca041f31b..05b5040faf85 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -112,6 +112,8 @@
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Rekhoda isikrini sakho?"</string>
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Rekhoda i-app eyodwa"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"Rekhoda sonke isikrini"</string>
+ <!-- no translation found for screenrecord_permission_dialog_option_text_entire_screen_for_display (3754611651558838691) -->
+ <skip />
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Uma urekhoda sonke isikrini sakho, noma yini evela esikrinini iyarekhodwa. Ngakho-ke qaphela ngezinto ezifana namaphasiwedi, imininingwane yenkokhelo, imilayezo, izithombe, nomsindo nevidiyo."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Uma urekhoda i-app, noma yini evezwa noma edlala kuleyo app iyarekhodwa. Ngakho-ke qaphela ngezinto ezifana namaphasiwedi, imininingwane yenkokhelo, imilayezo, izithombe, nomsindo nevidiyo."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Rekhoda isikrini"</string>
@@ -1413,9 +1415,15 @@
<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>
+ <!-- no translation found for shortcut_helper_customize_mode_title (1467657117101096033) -->
+ <skip />
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Sesha izinqamuleli"</string>
<string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ayikho imiphumela yosesho"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Goqa isithonjana"</string>
+ <!-- no translation found for shortcut_helper_customize_button_text (3124983502748069338) -->
+ <skip />
+ <!-- no translation found for shortcut_helper_done_button_text (7249905942125386191) -->
+ <skip />
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Nweba isithonjana"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"noma"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Hudula isibambi"</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index de547add1d1a..c5e205c8aa40 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -584,6 +584,12 @@
-->
<dimen name="shade_panel_width">412dp</dimen>
+ <!--
+ The horizontal distance between the shade overlay panel (both notifications and quick settings)
+ and the edge of the screen. This is zero only on Compact screens (< sw600dp).
+ -->
+ <dimen name="shade_panel_margin_horizontal">0dp</dimen>
+
<dimen name="brightness_mirror_height">48dp</dimen>
<dimen name="volume_dialog_panel_transparent_padding_right">8dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
index a33e0ac0b33a..44dd34a89303 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
@@ -32,6 +32,8 @@ import com.android.systemui.communal.domain.interactor.CommunalSceneTransitionIn
import com.android.systemui.communal.shared.log.CommunalMetricsLogger
import com.android.systemui.communal.shared.log.CommunalStatsLogProxyImpl
import com.android.systemui.communal.shared.model.CommunalScenes
+import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper
+import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelperImpl
import com.android.systemui.communal.util.CommunalColors
import com.android.systemui.communal.util.CommunalColorsImpl
import com.android.systemui.communal.widgets.CommunalWidgetModule
@@ -65,6 +67,7 @@ import kotlinx.coroutines.CoroutineScope
CommunalSettingsRepositoryModule::class,
CommunalSmartspaceRepositoryModule::class,
CommunalStartableModule::class,
+ GlanceableHubWidgetManagerModule::class,
]
)
interface CommunalModule {
@@ -91,6 +94,11 @@ interface CommunalModule {
impl: CommunalSceneTransitionInteractor
): CoreStartable
+ @Binds
+ fun bindGlanceableHubMultiUserHelper(
+ impl: GlanceableHubMultiUserHelperImpl
+ ): GlanceableHubMultiUserHelper
+
companion object {
const val LOGGABLE_PREFIXES = "loggable_prefixes"
const val LAUNCHER_PACKAGE = "launcher_package"
@@ -106,19 +114,14 @@ interface CommunalModule {
sceneKeys = listOf(CommunalScenes.Blank, CommunalScenes.Communal),
initialSceneKey = CommunalScenes.Blank,
navigationDistances =
- mapOf(
- CommunalScenes.Blank to 0,
- CommunalScenes.Communal to 1,
- ),
+ mapOf(CommunalScenes.Blank to 0, CommunalScenes.Communal to 1),
)
return SceneDataSourceDelegator(applicationScope, config)
}
@Provides
@SysUISingleton
- fun providesCommunalBackupUtils(
- @Application context: Context,
- ): CommunalBackupUtils {
+ fun providesCommunalBackupUtils(@Application context: Context): CommunalBackupUtils {
return CommunalBackupUtils(context)
}
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 6cbf5405f46b..2d19b026489c 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt
@@ -24,6 +24,7 @@ import com.android.systemui.communal.CommunalOngoingContentStartable
import com.android.systemui.communal.CommunalSceneStartable
import com.android.systemui.communal.log.CommunalLoggerStartable
import com.android.systemui.communal.widgets.CommunalAppWidgetHostStartable
+import com.android.systemui.dagger.qualifiers.PerUser
import dagger.Binds
import dagger.Module
import dagger.multibindings.ClassKey
@@ -48,6 +49,7 @@ interface CommunalStartableModule {
@Binds
@IntoMap
+ @PerUser
@ClassKey(CommunalAppWidgetHostStartable::class)
fun bindCommunalAppWidgetHostStartable(impl: CommunalAppWidgetHostStartable): CoreStartable
diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/GlanceableHubWidgetManagerModule.kt b/packages/SystemUI/src/com/android/systemui/communal/dagger/GlanceableHubWidgetManagerModule.kt
new file mode 100644
index 000000000000..8c0758398cb1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/GlanceableHubWidgetManagerModule.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.dagger
+
+import com.android.server.servicewatcher.ServiceWatcher.ServiceSupplier
+import com.android.systemui.communal.widgets.GlanceableHubWidgetManagerServiceInfo
+import com.android.systemui.communal.widgets.GlanceableHubWidgetManagerServiceSupplier
+import com.android.systemui.communal.widgets.GlanceableHubWidgetManagerServiceWatcherFactoryImpl
+import com.android.systemui.communal.widgets.ServiceWatcherFactory
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface GlanceableHubWidgetManagerModule {
+ @Binds
+ fun bindServiceSupplier(
+ impl: GlanceableHubWidgetManagerServiceSupplier
+ ): ServiceSupplier<GlanceableHubWidgetManagerServiceInfo?>
+
+ @Binds
+ fun bindServiceWatcherFactory(
+ impl: GlanceableHubWidgetManagerServiceWatcherFactoryImpl
+ ): ServiceWatcherFactory<GlanceableHubWidgetManagerServiceInfo?>
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt
index 17f4f0c83d6f..e72088f37fa7 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt
@@ -17,6 +17,7 @@
package com.android.systemui.communal.data.db
import android.content.Context
+import android.os.Process
import android.util.Log
import androidx.annotation.VisibleForTesting
import androidx.room.Database
@@ -24,6 +25,7 @@ import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
+import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelperImpl
import com.android.systemui.res.R
@Database(entities = [CommunalWidgetItem::class, CommunalItemRank::class], version = 4)
@@ -44,6 +46,11 @@ abstract class CommunalDatabase : RoomDatabase() {
* new instance is created.
*/
fun getInstance(context: Context, callback: Callback? = null): CommunalDatabase {
+ with(GlanceableHubMultiUserHelperImpl(Process.myUserHandle())) {
+ // Assert that the database is never accessed from a headless system user.
+ assertNotInHeadlessSystemUser()
+ }
+
if (instance == null) {
instance =
Room.databaseBuilder(
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt
index 258480e7fef5..3d40aa75b488 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt
@@ -25,6 +25,7 @@ import androidx.room.RoomDatabase
import androidx.room.Transaction
import androidx.room.Update
import androidx.sqlite.db.SupportSQLiteDatabase
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.communal.nano.CommunalHubState
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.widgets.CommunalWidgetHost
@@ -39,7 +40,6 @@ import javax.inject.Named
import javax.inject.Provider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
-import com.android.app.tracing.coroutines.launchTraced as launch
/**
* Callback that will be invoked when the Room database is created. Then the database will be
@@ -224,9 +224,9 @@ interface CommunalWidgetDao {
): Long {
val widgets = getWidgetsNow()
- // If rank is not specified, rank it last by finding the current maximum rank and increment
- // by 1. If the new widget is the first widget, set the rank to 0.
- val newRank = rank ?: widgets.keys.maxOfOrNull { it.rank + 1 } ?: 0
+ // If rank is not specified (null or less than 0), rank it last by finding the current
+ // maximum rank and increment by 1. If the new widget is the first widget, set rank to 0.
+ val newRank = rank?.takeIf { it >= 0 } ?: widgets.keys.maxOfOrNull { it.rank + 1 } ?: 0
// Shift widgets after [rank], unless widget is added at the end.
if (rank != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt
index e164587ce02d..29569f8b7df5 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt
@@ -21,6 +21,7 @@ import android.appwidget.AppWidgetProviderInfo
import android.content.ComponentName
import android.os.UserHandle
import android.os.UserManager
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.Flags.communalWidgetResizing
import com.android.systemui.common.data.repository.PackageChangeRepository
import com.android.systemui.common.shared.model.PackageInstallSession
@@ -51,11 +52,10 @@ import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
-import com.android.app.tracing.coroutines.launchTraced as launch
/** Encapsulates the state of widgets for communal mode. */
interface CommunalWidgetRepository {
- /** A flow of information about active communal widgets stored in database. */
+ /** A flow of the list of Glanceable Hub widgets ordered by rank. */
val communalWidgets: Flow<List<CommunalWidgetContentModel>>
/**
@@ -106,8 +106,12 @@ interface CommunalWidgetRepository {
fun resizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>)
}
+/**
+ * The local implementation of the [CommunalWidgetRepository] that should be injected in a
+ * foreground user process.
+ */
@SysUISingleton
-class CommunalWidgetRepositoryImpl
+class CommunalWidgetRepositoryLocalImpl
@Inject
constructor(
private val appWidgetHost: CommunalAppWidgetHost,
@@ -123,7 +127,7 @@ constructor(
private val defaultWidgetPopulation: DefaultWidgetPopulation,
) : CommunalWidgetRepository {
companion object {
- const val TAG = "CommunalWidgetRepository"
+ const val TAG = "CommunalWidgetRepositoryLocalImpl"
}
private val logger = Logger(logBuffer, TAG)
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryModule.kt
index b502fb11d7ac..824edcb26809 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryModule.kt
@@ -17,11 +17,24 @@
package com.android.systemui.communal.data.repository
-import dagger.Binds
+import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper
+import dagger.Lazy
import dagger.Module
+import dagger.Provides
@Module
interface CommunalWidgetRepositoryModule {
- @Binds
- fun communalWidgetRepository(impl: CommunalWidgetRepositoryImpl): CommunalWidgetRepository
+ companion object {
+ @Provides
+ fun provideCommunalWidgetRepository(
+ localImpl: Lazy<CommunalWidgetRepositoryLocalImpl>,
+ remoteImpl: Lazy<CommunalWidgetRepositoryRemoteImpl>,
+ helper: GlanceableHubMultiUserHelper,
+ ): CommunalWidgetRepository {
+ // Provide an implementation based on the current user.
+ return if (helper.glanceableHubHsumFlagEnabled && helper.isInHeadlessSystemUser())
+ remoteImpl.get()
+ else localImpl.get()
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryRemoteImpl.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryRemoteImpl.kt
new file mode 100644
index 000000000000..6682186c94f5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryRemoteImpl.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.data.repository
+
+import android.content.ComponentName
+import android.os.UserHandle
+import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
+import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper
+import com.android.systemui.communal.widgets.GlanceableHubWidgetManager
+import com.android.systemui.communal.widgets.WidgetConfigurator
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.launch
+
+/**
+ * The remote implementation of the [CommunalWidgetRepository] that should be injected in a headless
+ * system user process. This implementation receives widget data from and routes requests to the
+ * remote service in the foreground user.
+ */
+@SysUISingleton
+class CommunalWidgetRepositoryRemoteImpl
+@Inject
+constructor(
+ @Background private val bgScope: CoroutineScope,
+ private val glanceableHubWidgetManager: GlanceableHubWidgetManager,
+ glanceableHubMultiUserHelper: GlanceableHubMultiUserHelper,
+) : CommunalWidgetRepository {
+
+ init {
+ // This is the implementation for the headless system user. For the foreground user
+ // implementation see [CommunalWidgetRepositoryLocalImpl].
+ glanceableHubMultiUserHelper.assertInHeadlessSystemUser()
+ }
+
+ override val communalWidgets: Flow<List<CommunalWidgetContentModel>> =
+ glanceableHubWidgetManager.widgets
+
+ override fun addWidget(
+ provider: ComponentName,
+ user: UserHandle,
+ rank: Int?,
+ configurator: WidgetConfigurator?,
+ ) {
+ bgScope.launch { glanceableHubWidgetManager.addWidget(provider, user, rank, configurator) }
+ }
+
+ override fun deleteWidget(widgetId: Int) {
+ bgScope.launch { glanceableHubWidgetManager.deleteWidget(widgetId) }
+ }
+
+ override fun updateWidgetOrder(widgetIdToRankMap: Map<Int, Int>) {
+ bgScope.launch { glanceableHubWidgetManager.updateWidgetOrder(widgetIdToRankMap) }
+ }
+
+ override fun resizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) {
+ bgScope.launch {
+ glanceableHubWidgetManager.resizeWidget(appWidgetId, spanY, widgetIdToRankMap)
+ }
+ }
+
+ override fun restoreWidgets(oldToNewWidgetIdMap: Map<Int, Int>) {
+ throw IllegalStateException("Restore widgets should be performed on a foreground user")
+ }
+
+ override fun abortRestoreWidgets() {
+ throw IllegalStateException("Restore widgets should be performed on a foreground user")
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index dc248059b3d4..602fe307a1fe 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -40,7 +40,6 @@ import com.android.systemui.communal.shared.model.CommunalContentSize.THIRD
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
import com.android.systemui.communal.shared.model.EditModeState
-import com.android.systemui.communal.widgets.CommunalAppWidgetHost
import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
import com.android.systemui.communal.widgets.WidgetConfigurator
import com.android.systemui.dagger.SysUISingleton
@@ -108,7 +107,6 @@ constructor(
keyguardInteractor: KeyguardInteractor,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
communalSettingsInteractor: CommunalSettingsInteractor,
- private val appWidgetHost: CommunalAppWidgetHost,
private val editWidgetsActivityStarter: EditWidgetsActivityStarter,
private val userTracker: UserTracker,
private val activityStarter: ActivityStarter,
@@ -451,7 +449,6 @@ constructor(
appWidgetId = widget.appWidgetId,
rank = widget.rank,
providerInfo = widget.providerInfo,
- appWidgetHost = appWidgetHost,
inQuietMode = isQuietModeEnabled(widget.providerInfo.profile),
size = CommunalContentSize.toSize(widget.spanY),
)
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
index 4c2c094a4aea..30f580e472e8 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
@@ -23,7 +23,6 @@ import android.content.pm.ApplicationInfo
import android.graphics.Bitmap
import android.widget.RemoteViews
import com.android.systemui.communal.shared.model.CommunalContentSize
-import com.android.systemui.communal.widgets.CommunalAppWidgetHost
import java.util.UUID
/** Encapsulates data for a communal content. */
@@ -60,7 +59,6 @@ sealed interface CommunalContentModel {
override val appWidgetId: Int,
override val rank: Int,
val providerInfo: AppWidgetProviderInfo,
- val appWidgetHost: CommunalAppWidgetHost,
val inQuietMode: Boolean,
override val size: CommunalContentSize,
) : WidgetContent {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalWidgetContentModel.aidl b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalWidgetContentModel.aidl
new file mode 100644
index 000000000000..a215698eaeba
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalWidgetContentModel.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.shared.model;
+
+parcelable CommunalWidgetContentModel;
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalWidgetContentModel.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalWidgetContentModel.kt
index 0c9ea789f3d1..f23347d083d6 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalWidgetContentModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalWidgetContentModel.kt
@@ -19,21 +19,60 @@ package com.android.systemui.communal.shared.model
import android.appwidget.AppWidgetProviderInfo
import android.content.ComponentName
import android.graphics.Bitmap
+import android.os.Parcel
+import android.os.Parcelable
import android.os.UserHandle
/** Encapsulates data for a communal widget. */
-sealed interface CommunalWidgetContentModel {
+sealed interface CommunalWidgetContentModel : Parcelable {
val appWidgetId: Int
val rank: Int
val spanY: Int
+ // Used for distinguishing subtypes when reading from a parcel.
+ val type: Int
+
/** Widget is ready to display */
data class Available(
override val appWidgetId: Int,
val providerInfo: AppWidgetProviderInfo,
override val rank: Int,
override val spanY: Int,
- ) : CommunalWidgetContentModel
+ ) : CommunalWidgetContentModel {
+
+ override val type = TYPE_AVAILABLE
+
+ constructor(
+ parcel: Parcel
+ ) : this(
+ parcel.readInt(),
+ requireNotNull(parcel.readTypedObject(AppWidgetProviderInfo.CREATOR)),
+ parcel.readInt(),
+ parcel.readInt(),
+ )
+
+ override fun writeToParcel(parcel: Parcel, flags: Int) {
+ parcel.writeInt(type)
+ parcel.writeInt(appWidgetId)
+ parcel.writeTypedObject(providerInfo, flags)
+ parcel.writeInt(rank)
+ parcel.writeInt(spanY)
+ }
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ companion object CREATOR : Parcelable.Creator<Available> {
+ override fun createFromParcel(parcel: Parcel): Available {
+ return Available(parcel)
+ }
+
+ override fun newArray(size: Int): Array<Available?> {
+ return arrayOfNulls(size)
+ }
+ }
+ }
/** Widget is pending installation */
data class Pending(
@@ -43,5 +82,61 @@ sealed interface CommunalWidgetContentModel {
val icon: Bitmap?,
val user: UserHandle,
override val spanY: Int,
- ) : CommunalWidgetContentModel
+ ) : CommunalWidgetContentModel {
+
+ override val type = TYPE_PENDING
+
+ constructor(
+ parcel: Parcel
+ ) : this(
+ parcel.readInt(),
+ parcel.readInt(),
+ requireNotNull(parcel.readTypedObject(ComponentName.CREATOR)),
+ parcel.readTypedObject(Bitmap.CREATOR),
+ requireNotNull(parcel.readTypedObject(UserHandle.CREATOR)),
+ parcel.readInt(),
+ )
+
+ override fun writeToParcel(parcel: Parcel, flags: Int) {
+ parcel.writeInt(type)
+ parcel.writeInt(appWidgetId)
+ parcel.writeInt(rank)
+ parcel.writeTypedObject(componentName, flags)
+ parcel.writeTypedObject(icon, flags)
+ parcel.writeTypedObject(user, flags)
+ parcel.writeInt(spanY)
+ }
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ companion object CREATOR : Parcelable.Creator<Pending> {
+ override fun createFromParcel(parcel: Parcel): Pending {
+ return Pending(parcel)
+ }
+
+ override fun newArray(size: Int): Array<Pending?> {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+
+ // Used for distinguishing subtypes when reading from a parcel.
+ companion object CREATOR : Parcelable.Creator<CommunalWidgetContentModel> {
+ private const val TYPE_AVAILABLE = 0
+ private const val TYPE_PENDING = 1
+
+ override fun createFromParcel(parcel: Parcel): CommunalWidgetContentModel {
+ return when (val type = parcel.readInt()) {
+ TYPE_AVAILABLE -> Available(parcel)
+ TYPE_PENDING -> Pending(parcel)
+ else -> throw IllegalArgumentException("Unknown type: $type")
+ }
+ }
+
+ override fun newArray(size: Int): Array<CommunalWidgetContentModel?> {
+ return arrayOfNulls(size)
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/GlanceableHubMultiUserHelper.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/GlanceableHubMultiUserHelper.kt
new file mode 100644
index 000000000000..ef6a9ce6752b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/GlanceableHubMultiUserHelper.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.shared.model
+
+import android.os.UserHandle
+import android.os.UserManager
+import com.android.systemui.Flags.secondaryUserWidgetHost
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+
+/** Helper for multi-user / HSUM related functionality for the Glanceable Hub. */
+interface GlanceableHubMultiUserHelper {
+ /** Whether the Glanceable Hub in HSUM flag is enabled. */
+ val glanceableHubHsumFlagEnabled: Boolean
+
+ /** Whether the device is in headless system user mode. */
+ fun isHeadlessSystemUserMode(): Boolean
+
+ /** Whether the current process is running in the headless system user. */
+ fun isInHeadlessSystemUser(): Boolean
+
+ /**
+ * Asserts that the current process is running in the headless system user.
+ *
+ * Only throws an exception if [glanceableHubHsumFlagEnabled] is true.
+ */
+ @Throws(IllegalStateException::class) fun assertInHeadlessSystemUser()
+
+ /**
+ * Asserts that the current process is NOT running in the headless system user.
+ *
+ * Only throws an exception if [glanceableHubHsumFlagEnabled] is true.
+ */
+ @Throws(IllegalStateException::class) fun assertNotInHeadlessSystemUser()
+}
+
+@SysUISingleton
+class GlanceableHubMultiUserHelperImpl @Inject constructor(private val userHandle: UserHandle) :
+ GlanceableHubMultiUserHelper {
+
+ override val glanceableHubHsumFlagEnabled: Boolean = secondaryUserWidgetHost()
+
+ override fun isHeadlessSystemUserMode(): Boolean = UserManager.isHeadlessSystemUserMode()
+
+ override fun isInHeadlessSystemUser(): Boolean {
+ return isHeadlessSystemUserMode() && userHandle.isSystem
+ }
+
+ override fun assertInHeadlessSystemUser() {
+ if (glanceableHubHsumFlagEnabled) {
+ check(isInHeadlessSystemUser())
+ }
+ }
+
+ override fun assertNotInHeadlessSystemUser() {
+ if (glanceableHubHsumFlagEnabled) {
+ check(!isInHeadlessSystemUser())
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt b/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
index d5d3a927181b..cc6007b400f7 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
@@ -21,11 +21,14 @@ import android.os.Bundle
import android.util.SizeF
import com.android.app.tracing.coroutines.withContextTraced as withContext
import com.android.systemui.communal.domain.model.CommunalContentModel
+import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper
import com.android.systemui.communal.widgets.AppWidgetHostListenerDelegate
import com.android.systemui.communal.widgets.CommunalAppWidgetHost
import com.android.systemui.communal.widgets.CommunalAppWidgetHostView
+import com.android.systemui.communal.widgets.GlanceableHubWidgetManager
import com.android.systemui.communal.widgets.WidgetInteractionHandler
import com.android.systemui.dagger.qualifiers.UiBackground
+import dagger.Lazy
import java.util.concurrent.Executor
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
@@ -36,9 +39,11 @@ class WidgetViewFactory
constructor(
@UiBackground private val uiBgContext: CoroutineContext,
@UiBackground private val uiBgExecutor: Executor,
- private val appWidgetHost: CommunalAppWidgetHost,
+ private val appWidgetHostLazy: Lazy<CommunalAppWidgetHost>,
private val interactionHandler: WidgetInteractionHandler,
private val listenerFactory: AppWidgetHostListenerDelegate.Factory,
+ private val glanceableHubWidgetManagerLazy: Lazy<GlanceableHubWidgetManager>,
+ private val multiUserHelper: GlanceableHubMultiUserHelper,
) {
suspend fun createWidget(
context: Context,
@@ -51,9 +56,25 @@ constructor(
setExecutor(uiBgExecutor)
setAppWidget(model.appWidgetId, model.providerInfo)
}
- // Instead of setting the view as the listener directly, we wrap the view in a delegate
- // which ensures the callbacks always get called on the main thread.
- appWidgetHost.setListener(model.appWidgetId, listenerFactory.create(view))
+
+ if (
+ multiUserHelper.glanceableHubHsumFlagEnabled &&
+ multiUserHelper.isInHeadlessSystemUser()
+ ) {
+ // If the widget view is created in the headless system user, the widget host lives
+ // remotely in the foreground user, and therefore the host listener needs to be
+ // registered through the widget manager.
+ with(glanceableHubWidgetManagerLazy.get()) {
+ setAppWidgetHostListener(model.appWidgetId, listenerFactory.create(view))
+ }
+ } else {
+ // Instead of setting the view as the listener directly, we wrap the view in a
+ // delegate which ensures the callbacks always get called on the main thread.
+ with(appWidgetHostLazy.get()) {
+ setListener(model.appWidgetId, listenerFactory.create(view))
+ }
+ }
+
if (size != null) {
view.updateAppWidgetSize(
/* newOptions = */ Bundle(),
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHost.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHost.kt
index 4f9ed2f7dbf8..70e7947e1b70 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHost.kt
@@ -18,6 +18,8 @@ package com.android.systemui.communal.widgets
import android.appwidget.AppWidgetHost
import android.content.Context
+import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
import javax.annotation.concurrent.GuardedBy
@@ -25,7 +27,6 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
-import com.android.app.tracing.coroutines.launchTraced as launch
/** Communal app widget host that creates a [CommunalAppWidgetHostView]. */
class CommunalAppWidgetHost(
@@ -33,7 +34,14 @@ class CommunalAppWidgetHost(
private val backgroundScope: CoroutineScope,
hostId: Int,
logBuffer: LogBuffer,
+ glanceableHubMultiUserHelper: GlanceableHubMultiUserHelper,
) : AppWidgetHost(context, hostId) {
+
+ init {
+ // The app widget host should never be accessed from a headless system user.
+ glanceableHubMultiUserHelper.assertNotInHeadlessSystemUser()
+ }
+
private val logger = Logger(logBuffer, TAG)
private val _appWidgetIdToRemove = MutableSharedFlow<Int>()
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartable.kt
index 301da51c8082..dec7ba3a3eb1 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartable.kt
@@ -18,55 +18,118 @@ package com.android.systemui.communal.widgets
import com.android.systemui.CoreStartable
import com.android.systemui.communal.domain.interactor.CommunalInteractor
+import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
+import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.settings.UserTracker
+import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
+import com.android.systemui.util.kotlin.BooleanFlowOperators.not
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.sample
+import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.dropWhile
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.withContext
+// Started per user, so make sure injections are lazy to avoid instantiating unnecessary
+// dependencies.
@SysUISingleton
class CommunalAppWidgetHostStartable
@Inject
constructor(
- private val appWidgetHost: CommunalAppWidgetHost,
- private val communalWidgetHost: CommunalWidgetHost,
- private val communalInteractor: CommunalInteractor,
- private val userTracker: UserTracker,
+ private val appWidgetHostLazy: Lazy<CommunalAppWidgetHost>,
+ private val communalWidgetHostLazy: Lazy<CommunalWidgetHost>,
+ private val communalInteractorLazy: Lazy<CommunalInteractor>,
+ private val communalSettingsInteractorLazy: Lazy<CommunalSettingsInteractor>,
+ private val keyguardInteractorLazy: Lazy<KeyguardInteractor>,
+ private val userTrackerLazy: Lazy<UserTracker>,
@Background private val bgScope: CoroutineScope,
- @Main private val uiDispatcher: CoroutineDispatcher
+ @Main private val uiDispatcher: CoroutineDispatcher,
+ private val glanceableHubWidgetManagerLazy: Lazy<GlanceableHubWidgetManager>,
+ private val glanceableHubMultiUserHelper: GlanceableHubMultiUserHelper,
) : CoreStartable {
+ private val appWidgetHost by lazy { appWidgetHostLazy.get() }
+ private val communalWidgetHost by lazy { communalWidgetHostLazy.get() }
+ private val communalInteractor by lazy { communalInteractorLazy.get() }
+ private val communalSettingsInteractor by lazy { communalSettingsInteractorLazy.get() }
+ private val keyguardInteractor by lazy { keyguardInteractorLazy.get() }
+ private val userTracker by lazy { userTrackerLazy.get() }
+ private val glanceableHubWidgetManager by lazy { glanceableHubWidgetManagerLazy.get() }
+
override fun start() {
- anyOf(communalInteractor.isCommunalAvailable, communalInteractor.editModeOpen)
- // Only trigger updates on state changes, ignoring the initial false value.
- .pairwise(false)
- .filter { (previous, new) -> previous != new }
- .onEach { (_, shouldListen) -> updateAppWidgetHostActive(shouldListen) }
- .sample(communalInteractor.communalWidgets, ::Pair)
- .onEach { (withPrev, widgets) ->
- val (_, isActive) = withPrev
- // The validation is performed once the hub becomes active.
- if (isActive) {
- validateWidgetsAndDeleteOrphaned(widgets)
+ if (
+ glanceableHubMultiUserHelper.glanceableHubHsumFlagEnabled &&
+ glanceableHubMultiUserHelper.isInHeadlessSystemUser()
+ ) {
+ onStartInHeadlessSystemUser()
+ } else {
+ onStartInForegroundUser()
+ }
+ }
+
+ private fun onStartInForegroundUser() {
+ // Make the host active when communal becomes available, and delete widgets whose user has
+ // been removed from the system.
+ // Skipped in HSUM, because lifecycle of the host is controlled by the
+ // [GlanceableHubWidgetManagerService], and widgets are stored per user so no more orphaned
+ // widgets.
+ if (
+ !glanceableHubMultiUserHelper.glanceableHubHsumFlagEnabled ||
+ !glanceableHubMultiUserHelper.isHeadlessSystemUserMode()
+ ) {
+ anyOf(communalInteractor.isCommunalAvailable, communalInteractor.editModeOpen)
+ // Only trigger updates on state changes, ignoring the initial false value.
+ .pairwise(false)
+ .filter { (previous, new) -> previous != new }
+ .onEach { (_, shouldListen) -> updateAppWidgetHostActive(shouldListen) }
+ .sample(communalInteractor.communalWidgets, ::Pair)
+ .onEach { (withPrev, widgets) ->
+ val (_, isActive) = withPrev
+ // The validation is performed once the hub becomes active.
+ if (isActive) {
+ validateWidgetsAndDeleteOrphaned(widgets)
+ }
}
- }
- .launchIn(bgScope)
+ .launchIn(bgScope)
+ }
appWidgetHost.appWidgetIdToRemove
.onEach { appWidgetId -> communalInteractor.deleteWidget(id = appWidgetId) }
.launchIn(bgScope)
}
+ private fun onStartInHeadlessSystemUser() {
+ // Connection to the widget manager service in the foreground user should stay open as long
+ // as the Glanceable Hub is available.
+ allOf(
+ communalSettingsInteractor.isCommunalEnabled,
+ not(keyguardInteractor.isEncryptedOrLockdown),
+ )
+ .distinctUntilChanged()
+ // Drop the initial false
+ .dropWhile { !it }
+ .onEach { shouldRegister ->
+ if (shouldRegister) {
+ glanceableHubWidgetManager.register()
+ } else {
+ glanceableHubWidgetManager.unregister()
+ }
+ }
+ .launchIn(bgScope)
+ }
+
private suspend fun updateAppWidgetHostActive(active: Boolean) =
// Always ensure this is called on the main/ui thread.
withContext(uiDispatcher) {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt
index 0b8d9775675f..8c745f59e918 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt
@@ -26,6 +26,8 @@ import android.os.Bundle
import android.os.UserHandle
import android.widget.RemoteViews
import androidx.annotation.WorkerThread
+import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
@@ -38,7 +40,6 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
-import com.android.app.tracing.coroutines.launchTraced as launch
/**
* Widget host that interacts with AppWidget service and host to bind and provide info for widgets
@@ -52,7 +53,14 @@ constructor(
private val appWidgetHost: CommunalAppWidgetHost,
private val selectedUserInteractor: SelectedUserInteractor,
@CommunalLog logBuffer: LogBuffer,
+ glanceableHubMultiUserHelper: GlanceableHubMultiUserHelper,
) : CommunalAppWidgetHost.Observer {
+
+ init {
+ // The communal widget host should never be accessed from a headless system user.
+ glanceableHubMultiUserHelper.assertNotInHeadlessSystemUser()
+ }
+
companion object {
private const val TAG = "CommunalWidgetHost"
@@ -96,7 +104,7 @@ constructor(
bindWidget(
widgetId = id,
user = user ?: UserHandle(selectedUserInteractor.getSelectedUserId()),
- provider = provider
+ provider = provider,
)
) {
logger.d("Successfully bound the widget $provider")
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt
index f4962085000c..a235e7ae2b6a 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt
@@ -20,6 +20,7 @@ package com.android.systemui.communal.widgets
import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.res.Resources
+import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
@@ -46,8 +47,15 @@ interface CommunalWidgetModule {
@Application context: Context,
@Background backgroundScope: CoroutineScope,
@CommunalLog logBuffer: LogBuffer,
+ glanceableHubMultiUserHelper: GlanceableHubMultiUserHelper,
): CommunalAppWidgetHost {
- return CommunalAppWidgetHost(context, backgroundScope, APP_WIDGET_HOST_ID, logBuffer)
+ return CommunalAppWidgetHost(
+ context,
+ backgroundScope,
+ APP_WIDGET_HOST_ID,
+ logBuffer,
+ glanceableHubMultiUserHelper,
+ )
}
@SysUISingleton
@@ -58,6 +66,7 @@ interface CommunalWidgetModule {
appWidgetHost: CommunalAppWidgetHost,
selectedUserInteractor: SelectedUserInteractor,
@CommunalLog logBuffer: LogBuffer,
+ glanceableHubMultiUserHelper: GlanceableHubMultiUserHelper,
): CommunalWidgetHost {
return CommunalWidgetHost(
applicationScope,
@@ -65,6 +74,7 @@ interface CommunalWidgetModule {
appWidgetHost,
selectedUserInteractor,
logBuffer,
+ glanceableHubMultiUserHelper,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManager.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManager.kt
new file mode 100644
index 000000000000..202edf71fa11
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManager.kt
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.widgets
+
+import android.appwidget.AppWidgetHost.AppWidgetHostListener
+import android.appwidget.AppWidgetProviderInfo
+import android.content.ComponentName
+import android.os.IBinder
+import android.os.UserHandle
+import android.widget.RemoteViews
+import com.android.server.servicewatcher.ServiceWatcher
+import com.android.server.servicewatcher.ServiceWatcher.ServiceListener
+import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
+import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper
+import com.android.systemui.communal.widgets.IGlanceableHubWidgetManagerService.IAppWidgetHostListener
+import com.android.systemui.communal.widgets.IGlanceableHubWidgetManagerService.IGlanceableHubWidgetsListener
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.Logger
+import com.android.systemui.log.dagger.CommunalLog
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+
+/**
+ * Manages updates to Glanceable Hub widgets and requests to edit them from the headless system
+ * user.
+ *
+ * It communicates with the remote [GlanceableHubWidgetManagerService] which runs in the foreground
+ * user, and abstracts the IPC details from the rest of the system.
+ */
+@SysUISingleton
+class GlanceableHubWidgetManager
+@Inject
+constructor(
+ glanceableHubMultiUserHelper: GlanceableHubMultiUserHelper,
+ @CommunalLog logBuffer: LogBuffer,
+ serviceWatcherFactory: ServiceWatcherFactory<GlanceableHubWidgetManagerServiceInfo?>,
+) : ServiceListener<GlanceableHubWidgetManagerServiceInfo?> {
+
+ init {
+ // The manager should only be used in the headless system user.
+ glanceableHubMultiUserHelper.assertInHeadlessSystemUser()
+ }
+
+ private val logger = Logger(logBuffer, TAG)
+
+ private val serviceWatcher by lazy { serviceWatcherFactory.create(this) }
+
+ val widgets = conflatedCallbackFlow {
+ val callback =
+ object : IGlanceableHubWidgetsListener.Stub() {
+ override fun onWidgetsUpdated(widgets: List<CommunalWidgetContentModel>?) {
+ trySend(widgets ?: emptyList())
+ }
+ }
+ runOnService { service -> service.addWidgetsListener(callback) }
+ awaitClose { runOnService { service -> service.removeWidgetsListener(callback) } }
+ }
+
+ fun register() {
+ serviceWatcher.register()
+ }
+
+ fun unregister() {
+ serviceWatcher.unregister()
+ }
+
+ override fun onBind(binder: IBinder?, serviceInfo: GlanceableHubWidgetManagerServiceInfo?) {
+ logger.i("Service bound")
+ }
+
+ override fun onUnbind() {
+ logger.i("Service unbound")
+ }
+
+ /** Requests the foreground user to set a [AppWidgetHostListener] for the given app widget. */
+ fun setAppWidgetHostListener(appWidgetId: Int, listener: AppWidgetHostListener) =
+ runOnService { service ->
+ service.setAppWidgetHostListener(appWidgetId, createIAppWidgetHostListener(listener))
+ }
+
+ /** Requests the foreground user to add a widget. */
+ fun addWidget(
+ provider: ComponentName,
+ user: UserHandle,
+ rank: Int?,
+ configurator: WidgetConfigurator?,
+ ) = runOnService { service ->
+ // TODO(b/375036327): Add support for widget configuration
+ service.addWidget(provider, user, rank ?: -1)
+ }
+
+ /** Requests the foreground user to delete a widget. */
+ fun deleteWidget(appWidgetId: Int) = runOnService { service ->
+ service.deleteWidget(appWidgetId)
+ }
+
+ /** Requests the foreground user to update widget order. */
+ fun updateWidgetOrder(widgetIdToRankMap: Map<Int, Int>) = runOnService { service ->
+ service.updateWidgetOrder(
+ widgetIdToRankMap.keys.toIntArray(),
+ widgetIdToRankMap.values.toIntArray(),
+ )
+ }
+
+ /** Requests the foreground user to resize a widget. */
+ fun resizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) =
+ runOnService { service ->
+ service.resizeWidget(
+ appWidgetId,
+ spanY,
+ widgetIdToRankMap.keys.toIntArray(),
+ widgetIdToRankMap.values.toIntArray(),
+ )
+ }
+
+ private fun runOnService(block: (IGlanceableHubWidgetManagerService) -> Unit) {
+ serviceWatcher.runOnBinder(
+ object : ServiceWatcher.BinderOperation {
+ override fun run(binder: IBinder?) {
+ block(IGlanceableHubWidgetManagerService.Stub.asInterface(binder))
+ }
+
+ override fun onError(t: Throwable?) {
+ // TODO(b/375236794): handle failure in case service is unbound
+ }
+ }
+ )
+ }
+
+ private fun createIAppWidgetHostListener(
+ listener: AppWidgetHostListener
+ ): IAppWidgetHostListener {
+ return object : IAppWidgetHostListener.Stub() {
+ override fun onUpdateProviderInfo(appWidget: AppWidgetProviderInfo?) {
+ listener.onUpdateProviderInfo(appWidget)
+ }
+
+ override fun updateAppWidget(views: RemoteViews?) {
+ listener.updateAppWidget(views)
+ }
+
+ override fun updateAppWidgetDeferred(packageName: String?, appWidgetId: Int) {
+ listener.updateAppWidgetDeferred(packageName, appWidgetId)
+ }
+
+ override fun onViewDataChanged(viewId: Int) {
+ listener.onViewDataChanged(viewId)
+ }
+ }
+ }
+
+ companion object {
+ private const val TAG = "GlanceableHubWidgetManager"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerService.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerService.kt
new file mode 100644
index 000000000000..4d042fc277de
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerService.kt
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.widgets
+
+import android.appwidget.AppWidgetHost.AppWidgetHostListener
+import android.appwidget.AppWidgetProviderInfo
+import android.content.ComponentName
+import android.content.Intent
+import android.os.IBinder
+import android.os.RemoteCallbackList
+import android.os.UserHandle
+import android.widget.RemoteViews
+import androidx.lifecycle.LifecycleService
+import androidx.lifecycle.lifecycleScope
+import com.android.systemui.communal.data.repository.CommunalWidgetRepository
+import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper
+import com.android.systemui.communal.widgets.IGlanceableHubWidgetManagerService.IAppWidgetHostListener
+import com.android.systemui.communal.widgets.IGlanceableHubWidgetManagerService.IGlanceableHubWidgetsListener
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.Logger
+import com.android.systemui.log.dagger.CommunalLog
+import javax.inject.Inject
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+
+/**
+ * Service for the [GlanceableHubWidgetManager], which runs in a foreground user in Headless System
+ * User Mode (HSUM), manages widgets as the user who owns them, and communicates back to the
+ * headless system user, where these widgets are rendered.
+ */
+class GlanceableHubWidgetManagerService
+@Inject
+constructor(
+ private val widgetRepository: CommunalWidgetRepository,
+ private val appWidgetHost: CommunalAppWidgetHost,
+ private val communalWidgetHost: CommunalWidgetHost,
+ glanceableHubMultiUserHelper: GlanceableHubMultiUserHelper,
+ @CommunalLog logBuffer: LogBuffer,
+) : LifecycleService() {
+
+ init {
+ // The service should only run in a foreground user.
+ glanceableHubMultiUserHelper.assertNotInHeadlessSystemUser()
+ }
+
+ private val logger = Logger(logBuffer, TAG)
+ private val widgetListenersRegistry = WidgetListenerRegistry()
+
+ override fun onCreate() {
+ super.onCreate()
+
+ logger.i("Service created")
+
+ communalWidgetHost.startObservingHost()
+ appWidgetHost.startListening()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+
+ logger.i("Service destroyed")
+
+ appWidgetHost.stopListening()
+ communalWidgetHost.stopObservingHost()
+
+ // Cancel all widget listener jobs and unregister listeners
+ widgetListenersRegistry.kill()
+ }
+
+ override fun onBind(intent: Intent): IBinder? {
+ super.onBind(intent)
+ return WidgetManagerServiceBinder().asBinder()
+ }
+
+ private fun addWidgetsListenerInternal(listener: IGlanceableHubWidgetsListener?) {
+ if (listener == null) {
+ throw IllegalStateException("Listener cannot be null")
+ }
+
+ if (!listener.asBinder().isBinderAlive) {
+ throw IllegalStateException("Listener binder is dead")
+ }
+
+ val job =
+ widgetRepository.communalWidgets
+ .onEach { widgets -> listener.onWidgetsUpdated(widgets) }
+ .launchIn(lifecycleScope)
+ widgetListenersRegistry.register(listener, job)
+ }
+
+ private fun removeWidgetsListenerInternal(listener: IGlanceableHubWidgetsListener?) {
+ if (listener == null) {
+ throw IllegalStateException("Listener cannot be null")
+ }
+
+ widgetListenersRegistry.unregister(listener)
+ }
+
+ private fun setAppWidgetHostListenerInternal(
+ appWidgetId: Int,
+ listener: IAppWidgetHostListener?,
+ ) {
+ if (listener == null) {
+ throw IllegalStateException("Listener cannot be null")
+ }
+
+ appWidgetHost.setListener(appWidgetId, createListener(listener))
+ }
+
+ private fun addWidgetInternal(provider: ComponentName?, user: UserHandle?, rank: Int) {
+ if (provider == null) {
+ throw IllegalStateException("Provider cannot be null")
+ }
+
+ if (user == null) {
+ throw IllegalStateException("User cannot be null")
+ }
+
+ // TODO(b/375036327): Add support for widget configuration
+ widgetRepository.addWidget(provider, user, rank, configurator = null)
+ }
+
+ private fun deleteWidgetInternal(appWidgetId: Int) {
+ widgetRepository.deleteWidget(appWidgetId)
+ }
+
+ private fun updateWidgetOrderInternal(appWidgetIds: IntArray?, ranks: IntArray?) {
+ if (appWidgetIds == null || ranks == null) {
+ throw IllegalStateException("appWidgetIds and ranks cannot be null")
+ }
+
+ if (appWidgetIds.size != ranks.size) {
+ throw IllegalStateException("appWidgetIds and ranks must be the same size")
+ }
+
+ widgetRepository.updateWidgetOrder(appWidgetIds.zip(ranks).toMap())
+ }
+
+ private fun resizeWidgetInternal(
+ appWidgetId: Int,
+ spanY: Int,
+ appWidgetIds: IntArray?,
+ ranks: IntArray?,
+ ) {
+ if (appWidgetIds == null || ranks == null) {
+ throw IllegalStateException("appWidgetIds and ranks cannot be null")
+ }
+
+ if (appWidgetIds.size != ranks.size) {
+ throw IllegalStateException("appWidgetIds and ranks must be the same size")
+ }
+
+ widgetRepository.resizeWidget(appWidgetId, spanY, appWidgetIds.zip(ranks).toMap())
+ }
+
+ private fun createListener(listener: IAppWidgetHostListener): AppWidgetHostListener {
+ return object : AppWidgetHostListener {
+ override fun onUpdateProviderInfo(appWidget: AppWidgetProviderInfo?) {
+ listener.onUpdateProviderInfo(appWidget)
+ }
+
+ override fun updateAppWidget(views: RemoteViews?) {
+ listener.updateAppWidget(views)
+ }
+
+ override fun updateAppWidgetDeferred(packageName: String?, appWidgetId: Int) {
+ listener.updateAppWidgetDeferred(packageName, appWidgetId)
+ }
+
+ override fun onViewDataChanged(viewId: Int) {
+ listener.onViewDataChanged(viewId)
+ }
+ }
+ }
+
+ private inner class WidgetManagerServiceBinder : IGlanceableHubWidgetManagerService.Stub() {
+ override fun addWidgetsListener(listener: IGlanceableHubWidgetsListener?) {
+ val iden = clearCallingIdentity()
+
+ try {
+ addWidgetsListenerInternal(listener)
+ } finally {
+ restoreCallingIdentity(iden)
+ }
+ }
+
+ override fun removeWidgetsListener(listener: IGlanceableHubWidgetsListener?) {
+ val iden = clearCallingIdentity()
+
+ try {
+ removeWidgetsListenerInternal(listener)
+ } finally {
+ restoreCallingIdentity(iden)
+ }
+ }
+
+ override fun setAppWidgetHostListener(appWidgetId: Int, listener: IAppWidgetHostListener?) {
+ val iden = clearCallingIdentity()
+
+ try {
+ setAppWidgetHostListenerInternal(appWidgetId, listener)
+ } finally {
+ restoreCallingIdentity(iden)
+ }
+ }
+
+ override fun addWidget(provider: ComponentName?, user: UserHandle?, rank: Int) {
+ val iden = clearCallingIdentity()
+
+ try {
+ addWidgetInternal(provider, user, rank)
+ } finally {
+ restoreCallingIdentity(iden)
+ }
+ }
+
+ override fun deleteWidget(appWidgetId: Int) {
+ val iden = clearCallingIdentity()
+
+ try {
+ deleteWidgetInternal(appWidgetId)
+ } finally {
+ restoreCallingIdentity(iden)
+ }
+ }
+
+ override fun updateWidgetOrder(appWidgetIds: IntArray?, ranks: IntArray?) {
+ val iden = clearCallingIdentity()
+
+ try {
+ updateWidgetOrderInternal(appWidgetIds, ranks)
+ } finally {
+ restoreCallingIdentity(iden)
+ }
+ }
+
+ override fun resizeWidget(
+ appWidgetId: Int,
+ spanY: Int,
+ appWidgetIds: IntArray?,
+ ranks: IntArray?,
+ ) {
+ val iden = clearCallingIdentity()
+
+ try {
+ resizeWidgetInternal(appWidgetId, spanY, appWidgetIds, ranks)
+ } finally {
+ restoreCallingIdentity(iden)
+ }
+ }
+ }
+
+ /**
+ * Registry of widget listener binders, which handles canceling the job associated with a
+ * listener when it is unregistered, or when the binder is dead.
+ */
+ private class WidgetListenerRegistry : RemoteCallbackList<IGlanceableHubWidgetsListener>() {
+ private val jobs = mutableMapOf<IGlanceableHubWidgetsListener, Job>()
+
+ fun register(listener: IGlanceableHubWidgetsListener, job: Job) {
+ if (register(listener)) {
+ synchronized(jobs) { jobs[listener] = job }
+ } else {
+ job.cancel()
+ }
+ }
+
+ override fun unregister(listener: IGlanceableHubWidgetsListener?): Boolean {
+ synchronized(jobs) { jobs.remove(listener)?.cancel() }
+ return super.unregister(listener)
+ }
+
+ override fun onCallbackDied(listener: IGlanceableHubWidgetsListener?) {
+ synchronized(jobs) { jobs.remove(listener)?.cancel() }
+ super.onCallbackDied(listener)
+ }
+
+ override fun kill() {
+ synchronized(jobs) {
+ jobs.values.forEach { it.cancel() }
+ jobs.clear()
+ }
+ super.kill()
+ }
+ }
+
+ companion object {
+ private const val TAG = "GlanceableHubWidgetManagerService"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceInfo.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceInfo.kt
new file mode 100644
index 000000000000..d52761164a38
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceInfo.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.widgets
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Context.BIND_AUTO_CREATE
+import android.os.UserHandle
+import com.android.server.servicewatcher.ServiceWatcher
+
+/**
+ * Information about the [GlanceableHubWidgetManagerServiceInfo] used for binding with the
+ * [ServiceWatcher].
+ */
+class GlanceableHubWidgetManagerServiceInfo(context: Context, userHandle: UserHandle) :
+ ServiceWatcher.BoundServiceInfo(
+ /* action= */ null,
+ UserHandle.getUid(userHandle.identifier, UserHandle.getCallingAppId()),
+ ComponentName(context.packageName, GlanceableHubWidgetManagerService::class.java.name),
+ BIND_AUTO_CREATE,
+ )
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceSupplier.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceSupplier.kt
new file mode 100644
index 000000000000..ed77e6f5d7ea
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceSupplier.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.widgets
+
+import android.content.Context
+import com.android.server.servicewatcher.ServiceWatcher
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.settings.UserTracker
+import java.util.concurrent.Executor
+import javax.inject.Inject
+
+/**
+ * Supplies details about the [GlanceableHubWidgetManagerService] that the [ServiceWatcher] should
+ * bind to. Currently the service should only be bound if the current user is the main user.
+ */
+@SysUISingleton
+class GlanceableHubWidgetManagerServiceSupplier
+@Inject
+constructor(
+ @Application private val context: Context,
+ @Background private val bgExecutor: Executor,
+ private val userTracker: UserTracker,
+) : ServiceWatcher.ServiceSupplier<GlanceableHubWidgetManagerServiceInfo?>, UserTracker.Callback {
+
+ private var userAboutToSwitch = false
+ private var listener: ServiceWatcher.ServiceChangedListener? = null
+
+ override fun getServiceInfo(): GlanceableHubWidgetManagerServiceInfo? {
+ return GlanceableHubWidgetManagerServiceInfo(context, userTracker.userHandle)
+ }
+
+ override fun hasMatchingService(): Boolean {
+ // The service becomes unavailable immediately before a user switching is about to happen
+ // so that it is disconnected before the user process is terminated.
+ // It is also only available if the current user is the main user.
+ return !userAboutToSwitch && userTracker.userInfo.isMain
+ }
+
+ override fun register(listener: ServiceWatcher.ServiceChangedListener?) {
+ this.listener = listener
+ userTracker.addCallback(this, bgExecutor)
+ }
+
+ override fun unregister() {
+ listener = null
+ userTracker.removeCallback(this)
+ }
+
+ override fun onBeforeUserSwitching(newUser: Int) {
+ userAboutToSwitch = true
+ listener?.onServiceChanged()
+ }
+
+ override fun onUserChanged(newUser: Int, userContext: Context) {
+ userAboutToSwitch = false
+ listener?.onServiceChanged()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/IGlanceableHubWidgetManagerService.aidl b/packages/SystemUI/src/com/android/systemui/communal/widgets/IGlanceableHubWidgetManagerService.aidl
new file mode 100644
index 000000000000..e556472c78a7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/IGlanceableHubWidgetManagerService.aidl
@@ -0,0 +1,51 @@
+package com.android.systemui.communal.widgets;
+
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.os.UserHandle;
+import android.widget.RemoteViews;
+import com.android.systemui.communal.shared.model.CommunalWidgetContentModel;
+import java.util.List;
+
+// Interface for the [GlanceableHubWidgetManagerService], which runs in a foreground user in HSUM
+// and communicates with the headless system user.
+interface IGlanceableHubWidgetManagerService {
+
+ // Adds a listener for updates of Glanceable Hub widgets.
+ oneway void addWidgetsListener(in IGlanceableHubWidgetsListener listener);
+
+ // Removes a listener for updates of Glanceable Hub widgets.
+ oneway void removeWidgetsListener(in IGlanceableHubWidgetsListener listener);
+
+ // Sets a listener for updates on a specific widget.
+ oneway void setAppWidgetHostListener(int appWidgetId, in IAppWidgetHostListener listener);
+
+ // Requests to add a widget in the Glanceable Hub.
+ oneway void addWidget(in ComponentName provider, in UserHandle user, int rank);
+
+ // Requests to delete a widget from the Glanceable Hub.
+ oneway void deleteWidget(int appWidgetId);
+
+ // Requests to update the order of widgets in the Glanceable Hub.
+ oneway void updateWidgetOrder(in int[] appWidgetIds, in int[] ranks);
+
+ // Requests to resize a widget in the Glanceable Hub.
+ oneway void resizeWidget(int appWidgetId, int spanY, in int[] appWidgetIds, in int[] ranks);
+
+ // Listener for Glanceable Hub widget updates
+ oneway interface IGlanceableHubWidgetsListener {
+ // Called when widgets have updated.
+ void onWidgetsUpdated(in List<CommunalWidgetContentModel> widgets);
+ }
+
+ // Mirrors [AppWidgetHost#AppWidgetHostListener].
+ oneway interface IAppWidgetHostListener {
+ void onUpdateProviderInfo(in @nullable AppWidgetProviderInfo appWidget);
+
+ void updateAppWidget(in @nullable RemoteViews views);
+
+ void updateAppWidgetDeferred(in String packageName, int appWidgetId);
+
+ void onViewDataChanged(int viewId);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/ServiceWatcherFactory.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/ServiceWatcherFactory.kt
new file mode 100644
index 000000000000..f79cc87b19cb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/ServiceWatcherFactory.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.widgets
+
+import android.content.Context
+import android.os.Handler
+import com.android.server.servicewatcher.ServiceWatcher
+import com.android.server.servicewatcher.ServiceWatcher.BoundServiceInfo
+import com.android.server.servicewatcher.ServiceWatcher.ServiceSupplier
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import javax.inject.Inject
+
+/** Factory for creating a [ServiceWatcher]. */
+interface ServiceWatcherFactory<TBoundService : BoundServiceInfo?> {
+ fun create(listener: ServiceWatcher.ServiceListener<TBoundService?>): ServiceWatcher
+}
+
+/** Implementation of the [ServiceWatcherFactory] for the [GlanceableHubWidgetManagerService]. */
+@SysUISingleton
+class GlanceableHubWidgetManagerServiceWatcherFactoryImpl
+@Inject
+constructor(
+ @Application private val context: Context,
+ @Background private val handler: Handler,
+ private val supplier: ServiceSupplier<GlanceableHubWidgetManagerServiceInfo?>,
+) : ServiceWatcherFactory<GlanceableHubWidgetManagerServiceInfo?> {
+
+ override fun create(
+ listener: ServiceWatcher.ServiceListener<GlanceableHubWidgetManagerServiceInfo?>
+ ): ServiceWatcher {
+ return ServiceWatcher.create(
+ context,
+ handler,
+ GlanceableHubWidgetManagerService::class.java.simpleName,
+ supplier,
+ listener,
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetConfigurationController.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetConfigurationController.kt
index 3e68479e717a..d157cd7acb76 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetConfigurationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetConfigurationController.kt
@@ -21,8 +21,10 @@ import android.app.ActivityOptions
import android.content.ActivityNotFoundException
import android.window.SplashScreen
import androidx.activity.ComponentActivity
+import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.util.nullableAtomicReference
+import dagger.Lazy
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@@ -38,8 +40,9 @@ class WidgetConfigurationController
@AssistedInject
constructor(
@Assisted private val activity: ComponentActivity,
- private val appWidgetHost: CommunalAppWidgetHost,
- @Background private val bgDispatcher: CoroutineDispatcher
+ private val appWidgetHostLazy: Lazy<CommunalAppWidgetHost>,
+ @Background private val bgDispatcher: CoroutineDispatcher,
+ private val glanceableHubMultiUserHelper: GlanceableHubMultiUserHelper,
) : WidgetConfigurator {
@AssistedFactory
fun interface Factory {
@@ -62,13 +65,21 @@ constructor(
}
try {
- appWidgetHost.startAppWidgetConfigureActivityForResult(
- activity,
- appWidgetId,
- 0,
- REQUEST_CODE,
- options.toBundle()
- )
+ // TODO(b/375036327): Add support for widget configuration
+ if (
+ !glanceableHubMultiUserHelper.glanceableHubHsumFlagEnabled ||
+ !glanceableHubMultiUserHelper.isInHeadlessSystemUser()
+ ) {
+ with(appWidgetHostLazy.get()) {
+ startAppWidgetConfigureActivityForResult(
+ activity,
+ appWidgetId,
+ 0,
+ REQUEST_CODE,
+ options.toBundle(),
+ )
+ }
+ }
} catch (e: ActivityNotFoundException) {
setConfigurationResult(Activity.RESULT_CANCELED)
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
index 904d5898fcf8..8f01775bc969 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
@@ -19,6 +19,7 @@ package com.android.systemui.dagger;
import android.app.Service;
import com.android.systemui.SystemUIService;
+import com.android.systemui.communal.widgets.GlanceableHubWidgetManagerService;
import com.android.systemui.doze.DozeService;
import com.android.systemui.dreams.DreamOverlayService;
import com.android.systemui.dump.SystemUIAuxiliaryDumpService;
@@ -93,4 +94,10 @@ public abstract class DefaultServiceBinder {
@ClassKey(IssueRecordingService.class)
public abstract Service bindIssueRecordingService(IssueRecordingService service);
+ /** Inject into GlanceableHubWidgetManagerService */
+ @Binds
+ @IntoMap
+ @ClassKey(GlanceableHubWidgetManagerService.class)
+ public abstract Service bindGlanceableHubWidgetManagerService(
+ GlanceableHubWidgetManagerService service);
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt
index a08588750f85..12dd58176a71 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt
@@ -19,12 +19,14 @@ package com.android.systemui.keyboard.shortcut.data.repository
import android.content.Context
import android.graphics.drawable.Icon
import android.hardware.input.InputManager
+import android.hardware.input.KeyGlyphMap
import android.util.Log
import android.view.InputDevice
import android.view.KeyCharacterMap
import android.view.KeyEvent
import android.view.KeyboardShortcutGroup
import android.view.KeyboardShortcutInfo
+import com.android.systemui.Flags.shortcutHelperKeyGlyph
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyboard.shortcut.data.source.KeyboardShortcutGroupsSource
@@ -142,7 +144,10 @@ constructor(
return if (type == null) {
null
} else {
+ val keyGlyphMap =
+ if (shortcutHelperKeyGlyph()) inputManager.getKeyGlyphMap(inputDevice.id) else null
toShortcutCategory(
+ keyGlyphMap,
inputDevice.keyCharacterMap,
type,
groups,
@@ -163,6 +168,7 @@ constructor(
}
private fun toShortcutCategory(
+ keyGlyphMap: KeyGlyphMap?,
keyCharacterMap: KeyCharacterMap,
type: ShortcutCategoryType,
shortcutGroups: List<KeyboardShortcutGroup>,
@@ -175,6 +181,7 @@ constructor(
ShortcutSubCategory(
shortcutGroup.label.toString(),
toShortcuts(
+ keyGlyphMap,
keyCharacterMap,
shortcutGroup.items,
keepIcons,
@@ -192,6 +199,7 @@ constructor(
}
private fun toShortcuts(
+ keyGlyphMap: KeyGlyphMap?,
keyCharacterMap: KeyCharacterMap,
infoList: List<KeyboardShortcutInfo>,
keepIcons: Boolean,
@@ -203,14 +211,16 @@ constructor(
// keycode, or they could have a baseCharacter instead of a keycode.
it.keycode == KeyEvent.KEYCODE_UNKNOWN || supportedKeyCodes.contains(it.keycode)
}
- .mapNotNull { toShortcut(keyCharacterMap, it, keepIcons) }
+ .mapNotNull { toShortcut(keyGlyphMap, keyCharacterMap, it, keepIcons) }
private fun toShortcut(
+ keyGlyphMap: KeyGlyphMap?,
keyCharacterMap: KeyCharacterMap,
shortcutInfo: KeyboardShortcutInfo,
keepIcon: Boolean,
): Shortcut? {
- val shortcutCommand = toShortcutCommand(keyCharacterMap, shortcutInfo) ?: return null
+ val shortcutCommand =
+ toShortcutCommand(keyGlyphMap, keyCharacterMap, shortcutInfo) ?: return null
return Shortcut(
label = shortcutInfo.label!!.toString(),
icon = toShortcutIcon(keepIcon, shortcutInfo),
@@ -235,6 +245,7 @@ constructor(
}
private fun toShortcutCommand(
+ keyGlyphMap: KeyGlyphMap?,
keyCharacterMap: KeyCharacterMap,
info: KeyboardShortcutInfo,
): ShortcutCommand? {
@@ -242,7 +253,7 @@ constructor(
var remainingModifiers = info.modifiers
SUPPORTED_MODIFIERS.forEach { supportedModifier ->
if ((supportedModifier and remainingModifiers) != 0) {
- keys += toShortcutModifierKey(supportedModifier) ?: return null
+ keys += toShortcutModifierKey(keyGlyphMap, supportedModifier) ?: return null
// "Remove" the modifier from the remaining modifiers
remainingModifiers = remainingModifiers and supportedModifier.inv()
}
@@ -253,7 +264,9 @@ constructor(
return null
}
if (info.keycode != 0 || info.baseCharacter > Char.MIN_VALUE) {
- keys += toShortcutKey(keyCharacterMap, info.keycode, info.baseCharacter) ?: return null
+ keys +=
+ toShortcutKey(keyGlyphMap, keyCharacterMap, info.keycode, info.baseCharacter)
+ ?: return null
}
if (keys.isEmpty()) {
Log.wtf(TAG, "No keys for $info")
@@ -262,10 +275,15 @@ constructor(
return ShortcutCommand(keys)
}
- private fun toShortcutModifierKey(modifierMask: Int): ShortcutKey? {
+ private fun toShortcutModifierKey(keyGlyphMap: KeyGlyphMap?, modifierMask: Int): ShortcutKey? {
+ val modifierDrawable = keyGlyphMap?.getDrawableForModifierState(context, modifierMask)
+ if (modifierDrawable != null) {
+ return ShortcutKey.Icon.DrawableIcon(drawable = modifierDrawable)
+ }
+
val iconResId = ShortcutHelperKeys.keyIcons[modifierMask]
if (iconResId != null) {
- return ShortcutKey.Icon(iconResId)
+ return ShortcutKey.Icon.ResIdIcon(iconResId)
}
val modifierLabel = ShortcutHelperKeys.modifierLabels[modifierMask]
@@ -277,13 +295,19 @@ constructor(
}
private fun toShortcutKey(
+ keyGlyphMap: KeyGlyphMap?,
keyCharacterMap: KeyCharacterMap,
keyCode: Int,
baseCharacter: Char = Char.MIN_VALUE,
): ShortcutKey? {
+ val keycodeDrawable = keyGlyphMap?.getDrawableForKeycode(context, keyCode)
+ if (keycodeDrawable != null) {
+ return ShortcutKey.Icon.DrawableIcon(drawable = keycodeDrawable)
+ }
+
val iconResId = ShortcutHelperKeys.keyIcons[keyCode]
if (iconResId != null) {
- return ShortcutKey.Icon(iconResId)
+ return ShortcutKey.Icon.ResIdIcon(iconResId)
}
if (baseCharacter > Char.MIN_VALUE) {
return ShortcutKey.Text(baseCharacter.uppercase())
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt
index eddac4d4ad73..05ff0cc30a44 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt
@@ -70,7 +70,7 @@ class MultitaskingShortcutsSource @Inject constructor(@Main private val resource
},
// Change split screen focus to LHS:
// - Meta + Alt + Left arrow
- shortcutInfo(resources.getString(R.string.system_multitasking_splitscreen_focus_rhs)) {
+ shortcutInfo(resources.getString(R.string.system_multitasking_splitscreen_focus_lhs)) {
command(META_META_ON or META_ALT_ON, KEYCODE_DPAD_LEFT)
},
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCommand.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCommand.kt
index e5b8096f2403..28451ae2bc14 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCommand.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCommand.kt
@@ -28,7 +28,7 @@ class ShortcutCommandBuilder {
}
fun key(@DrawableRes drawableResId: Int) {
- keys += ShortcutKey.Icon(drawableResId)
+ keys += ShortcutKey.Icon.ResIdIcon(drawableResId)
}
fun build() = ShortcutCommand(keys)
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutKey.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutKey.kt
index 1abb78c54b99..1a609eab7da3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutKey.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutKey.kt
@@ -16,10 +16,15 @@
package com.android.systemui.keyboard.shortcut.shared.model
+import android.graphics.drawable.Drawable
import androidx.annotation.DrawableRes
sealed interface ShortcutKey {
data class Text(val value: String) : ShortcutKey
- data class Icon(@DrawableRes val drawableResId: Int) : ShortcutKey
+ sealed interface Icon : ShortcutKey {
+ data class ResIdIcon(@DrawableRes val drawableResId: Int) : Icon
+
+ data class DrawableIcon(val drawable: Drawable) : Icon
+ }
}
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 d53705605901..abddc7059ece 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
@@ -647,7 +647,11 @@ private fun BoxScope.ShortcutTextKey(key: ShortcutKey.Text) {
@Composable
private fun BoxScope.ShortcutIconKey(key: ShortcutKey.Icon) {
Icon(
- painter = painterResource(key.drawableResId),
+ painter =
+ when (key) {
+ is ShortcutKey.Icon.ResIdIcon -> painterResource(key.drawableResId)
+ is ShortcutKey.Icon.DrawableIcon -> rememberDrawablePainter(drawable = key.drawable)
+ },
contentDescription = null,
modifier = Modifier.align(Alignment.Center).padding(6.dp),
)
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
index c70cd0a3a11b..47dacae6e0a0 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
@@ -131,7 +131,9 @@ public class MediaProjectionPermissionActivity extends Activity {
// This activity is launched directly by an app, or system server. System server provides
// the package name through the intent if so.
- if (mPackageName == null) {
+ if (mPackageName == null || (
+ com.android.systemui.Flags.mediaProjectionRequestAttributionFix()
+ && getCallingPackage() == null)) {
if (launchingIntent.hasExtra(EXTRA_PACKAGE_REUSING_GRANTED_CONSENT)) {
mPackageName = launchingIntent.getStringExtra(
EXTRA_PACKAGE_REUSING_GRANTED_CONSENT);
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 5229acc5f876..f3c6190d2f7b 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
@@ -19,6 +19,7 @@
package com.android.systemui.scene.domain.startable
import android.app.StatusBarManager
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.SceneKey
import com.android.internal.logging.UiEventLogger
@@ -102,7 +103,6 @@ import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.stateIn
-import com.android.app.tracing.coroutines.launchTraced as launch
/**
* Hooks up business logic that manipulates the state of the [SceneInteractor] for the system UI
@@ -300,7 +300,7 @@ constructor(
bouncerInteractor.onImeHiddenByUser.collectLatest {
if (sceneInteractor.currentScene.value == Scenes.Bouncer) {
sceneInteractor.changeScene(
- toScene = Scenes.Lockscreen, // TODO(b/336581871): add sceneState?
+ toScene = Scenes.Lockscreen,
loggingReason = "IME hidden",
)
}
@@ -318,7 +318,6 @@ constructor(
when {
isAnySimLocked -> {
switchToScene(
- // TODO(b/336581871): add sceneState?
targetSceneKey = Scenes.Bouncer,
loggingReason = "Need to authenticate locked SIM card.",
)
@@ -326,7 +325,6 @@ constructor(
unlockStatus.isUnlocked &&
deviceEntryInteractor.canSwipeToEnter.value == false -> {
switchToScene(
- // TODO(b/336581871): add sceneState?
targetSceneKey = Scenes.Gone,
loggingReason =
"All SIM cards unlocked and device already unlocked and " +
@@ -335,7 +333,6 @@ constructor(
}
else -> {
switchToScene(
- // TODO(b/336581871): add sceneState?
targetSceneKey = Scenes.Lockscreen,
loggingReason =
"All SIM cards unlocked and device still locked" +
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
index 49fa80c02d21..5b06ad2d1453 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
@@ -17,6 +17,7 @@
package com.android.systemui.shade
import android.view.MotionEvent
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.assist.AssistManager
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
@@ -39,7 +40,6 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.first
-import com.android.app.tracing.coroutines.launchTraced as launch
import kotlinx.coroutines.withContext
/**
@@ -136,7 +136,6 @@ constructor(
}
private fun animateCollapseShadeInternal() {
- // TODO(b/336581871): add sceneState?
shadeInteractor.collapseEitherShade(
loggingReason = "ShadeController.animateCollapseShade",
transitionKey = SlightlyFasterShadeCollapse,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt
index 3a483f460db7..f1513071de65 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt
@@ -41,7 +41,6 @@ constructor(
} else {
Scenes.Shade
}
- // TODO(b/336581871): add sceneState?
sceneInteractor.changeScene(key, "animateCollapseQs")
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/CommandQueueInitializer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/CommandQueueInitializer.kt
index 57c8bc6133e6..614f0f48d1fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/CommandQueueInitializer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/CommandQueueInitializer.kt
@@ -46,7 +46,7 @@ constructor(
) : CoreStartable {
override fun start() {
- StatusBarSimpleFragment.assertInNewMode()
+ StatusBarConnectedDisplays.assertInNewMode()
val result: RegisterStatusBarResult =
try {
barService.registerStatusBar(commandQueue)
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 aa2a08f980f9..08d177f933c1 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
@@ -1987,6 +1987,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mColorUpdateLogger = colorUpdateLogger;
mDismissibilityProvider = dismissibilityProvider;
mFeatureFlags = featureFlags;
+ setHapticFeedbackEnabled(!com.android.systemui.Flags.msdlFeedback());
}
private void initDimens() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index 23a2facf4c5a..baad616cbf02 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -64,6 +64,9 @@ import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
import com.android.systemui.util.time.SystemClock;
import com.android.systemui.wmshell.BubblesManager;
+import com.google.android.msdl.data.model.MSDLToken;
+import com.google.android.msdl.domain.MSDLPlayer;
+
import java.util.List;
import java.util.Optional;
@@ -114,6 +117,7 @@ public class ExpandableNotificationRowController implements NotifViewController
private final NotificationDismissibilityProvider mDismissibilityProvider;
private final IStatusBarService mStatusBarService;
private final UiEventLogger mUiEventLogger;
+ private final MSDLPlayer mMSDLPlayer;
private final NotificationSettingsController mSettingsController;
@@ -273,7 +277,8 @@ public class ExpandableNotificationRowController implements NotifViewController
ExpandableNotificationRowDragController dragController,
NotificationDismissibilityProvider dismissibilityProvider,
IStatusBarService statusBarService,
- UiEventLogger uiEventLogger) {
+ UiEventLogger uiEventLogger,
+ MSDLPlayer msdlPlayer) {
mView = view;
mListContainer = listContainer;
mRemoteInputViewSubcomponentFactory = rivSubcomponentFactory;
@@ -309,6 +314,7 @@ public class ExpandableNotificationRowController implements NotifViewController
mDismissibilityProvider = dismissibilityProvider;
mStatusBarService = statusBarService;
mUiEventLogger = uiEventLogger;
+ mMSDLPlayer = msdlPlayer;
}
/**
@@ -352,6 +358,9 @@ public class ExpandableNotificationRowController implements NotifViewController
}
mView.setLongPressListener((v, x, y, item) -> {
+ if (com.android.systemui.Flags.msdlFeedback()) {
+ mMSDLPlayer.playToken(MSDLToken.LONG_PRESS, null);
+ }
if (mView.isSummaryWithChildren()) {
mView.expandNotification();
return true;
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 f02f7f736668..57af8ea19722 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
@@ -797,7 +797,7 @@ public class NotificationStackScrollLayout
&& !onKeyguard()
&& mUpcomingStatusBarState != StatusBarState.KEYGUARD
// quick settings don't affect notifications when not in full screen
- && (mQsExpansionFraction != 1 || !mQsFullScreen)
+ && (getQsExpansionFraction() != 1 || !mQsFullScreen)
&& !mScreenOffAnimationController.shouldHideNotificationsFooter()
&& !mIsRemoteInputActive;
}
@@ -1528,7 +1528,7 @@ public class NotificationStackScrollLayout
float fraction = mAmbientState.getExpansionFraction();
// If we are on quick settings, we need to quickly hide it to show the bouncer to avoid an
// overlap. Otherwise, we maintain the normal fraction for smoothness.
- if (mAmbientState.isBouncerInTransit() && mQsExpansionFraction > 0f) {
+ if (mAmbientState.isBouncerInTransit() && getQsExpansionFraction() > 0f) {
fraction = BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(fraction);
}
final float stackY = MathUtils.lerp(0, endTopPosition, fraction);
@@ -1552,7 +1552,7 @@ public class NotificationStackScrollLayout
}
updateInterpolatedStackHeight(endHeight, fraction);
} else {
- if (mQsExpansionFraction <= 0 && !shouldSkipHeightUpdate()) {
+ if (getQsExpansionFraction() <= 0 && !shouldSkipHeightUpdate()) {
final float endHeight = updateStackEndHeight(
getHeight(), getEmptyBottomMarginInternal(), getTopPadding());
updateInterpolatedStackHeight(endHeight, fraction);
@@ -1705,7 +1705,7 @@ public class NotificationStackScrollLayout
stackHeight = (int) height;
} else {
stackHeight = (int) NotificationUtils.interpolate(stackStartPosition,
- stackEndPosition, mQsExpansionFraction);
+ stackEndPosition, getQsExpansionFraction());
}
}
} else {
@@ -5271,17 +5271,22 @@ public class NotificationStackScrollLayout
return mQsFullScreen;
}
+ private float getQsExpansionFraction() {
+ SceneContainerFlag.assertInLegacyMode();
+ return mQsExpansionFraction;
+ }
+
public void setQsExpansionFraction(float qsExpansionFraction) {
SceneContainerFlag.assertInLegacyMode();
- boolean footerAffected = mQsExpansionFraction != qsExpansionFraction
- && (mQsExpansionFraction == 1 || qsExpansionFraction == 1);
+ boolean footerAffected = getQsExpansionFraction() != qsExpansionFraction
+ && (getQsExpansionFraction() == 1 || qsExpansionFraction == 1);
mQsExpansionFraction = qsExpansionFraction;
updateUseRoundedRectClipping();
// If notifications are scrolled,
// clear out scrollY by the time we push notifications offscreen
if (getOwnScrollY() > 0) {
- setOwnScrollY((int) MathUtils.lerp(getOwnScrollY(), 0, mQsExpansionFraction));
+ setOwnScrollY((int) MathUtils.lerp(getOwnScrollY(), 0, getQsExpansionFraction()));
}
if (!FooterViewRefactor.isEnabled() && footerAffected) {
updateFooter();
@@ -5514,7 +5519,6 @@ public class NotificationStackScrollLayout
println(pw, "suppressChildrenMeasureLayout", mSuppressChildrenMeasureAndLayout);
println(pw, "scrollY", mAmbientState.getScrollY());
println(pw, "showShelfOnly", mShouldShowShelfOnly);
- println(pw, "qsExpandFraction", mQsExpansionFraction);
println(pw, "isCurrentUserSetup", mIsCurrentUserSetup);
println(pw, "hideAmount", mAmbientState.getHideAmount());
println(pw, "ambientStateSwipingUp", mAmbientState.isSwipingUp());
@@ -5550,6 +5554,7 @@ public class NotificationStackScrollLayout
println(pw, "contentHeight", getContentHeight());
println(pw, "topPadding", getTopPadding());
println(pw, "maxTopPadding", getMaxTopPadding());
+ println(pw, "qsExpandFraction", getQsExpansionFraction());
}
});
pw.println();
@@ -5622,7 +5627,9 @@ public class NotificationStackScrollLayout
pw.println("mIsCurrentUserSetup: " + mIsCurrentUserSetup);
pw.println("onKeyguard: " + onKeyguard());
pw.println("mUpcomingStatusBarState: " + mUpcomingStatusBarState);
- pw.println("mQsExpansionFraction: " + mQsExpansionFraction);
+ if (!SceneContainerFlag.isEnabled()) {
+ pw.println("QsExpansionFraction: " + getQsExpansionFraction());
+ }
pw.println("mQsFullScreen: " + mQsFullScreen);
pw.println(
"mScreenOffAnimationController"
@@ -6246,7 +6253,8 @@ public class NotificationStackScrollLayout
if (SceneContainerFlag.isEnabled()) return;
// We don't want to clip notifications when QS is expanded, because incoming heads up on
// the bottom would be clipped otherwise
- boolean qsAllowsClipping = mQsExpansionFraction < 0.5f || mShouldUseSplitNotificationShade;
+ boolean qsAllowsClipping =
+ getQsExpansionFraction() < 0.5f || mShouldUseSplitNotificationShade;
boolean clip = mIsExpanded && qsAllowsClipping;
if (clip != mShouldUseRoundedRectClipping) {
mShouldUseRoundedRectClipping = clip;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index 96d0d766d780..827e2bfeba0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -228,9 +228,14 @@ constructor(
configurationInteractor.onAnyConfigurationChange,
) { isShadeLayoutWide, shadeMode, _ ->
with(context.resources) {
- // TODO(b/338033836): Define separate horizontal margins for dual shade.
val marginHorizontal =
- getDimensionPixelSize(R.dimen.notification_panel_margin_horizontal)
+ getDimensionPixelSize(
+ if (shadeMode is Dual) {
+ R.dimen.shade_panel_margin_horizontal
+ } else {
+ R.dimen.notification_panel_margin_horizontal
+ }
+ )
val horizontalPosition =
when (shadeMode) {
@@ -248,10 +253,7 @@ constructor(
ConfigurationBasedDimensions(
horizontalPosition = horizontalPosition,
- marginStart =
- if (horizontalPosition is HorizontalPosition.EdgeToEdge)
- marginHorizontal
- else 0,
+ marginStart = if (shadeMode is Split) 0 else marginHorizontal,
marginEnd = marginHorizontal,
marginBottom =
getDimensionPixelSize(R.dimen.notification_panel_margin_bottom),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 9cda199d5279..0c511aeae3e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -1348,6 +1348,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
if (!canHandleBackPressed()) {
return;
}
+ mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
boolean hideBouncerOverDream = isBouncerShowing()
&& mDreamOverlayStateController.isOverlayActive();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
index e4a75beca9f9..23f3482d40bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
@@ -143,7 +143,7 @@ interface StatusBarPhoneModule {
fun commandQueueInitializerCoreStartable(
initializerLazy: Lazy<CommandQueueInitializer>
): CoreStartable {
- return if (StatusBarSimpleFragment.isEnabled) {
+ return if (StatusBarConnectedDisplays.isEnabled) {
initializerLazy.get()
} else {
CoreStartable.NOP
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt
index 76389f39e484..b033b362f4c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt
@@ -46,7 +46,7 @@ import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.statusbar.policy.ui.dialog.viewmodel.ModeTileViewModel
@Composable
-fun ModeTile(viewModel: ModeTileViewModel) {
+fun ModeTile(viewModel: ModeTileViewModel, modifier: Modifier = Modifier) {
val tileColor: Color by
animateColorAsState(
if (viewModel.enabled) MaterialTheme.colorScheme.primary
@@ -59,7 +59,7 @@ fun ModeTile(viewModel: ModeTileViewModel) {
)
CompositionLocalProvider(LocalContentColor provides contentColor) {
- Surface(color = tileColor, shape = RoundedCornerShape(16.dp)) {
+ Surface(color = tileColor, shape = RoundedCornerShape(16.dp), modifier = modifier) {
Row(
modifier =
Modifier.combinedClickable(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt
index 903c7e1537bc..16f24f1d5821 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt
@@ -17,29 +17,74 @@
package com.android.systemui.statusbar.policy.ui.dialog.composable
import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
+import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
+import androidx.compose.foundation.pager.HorizontalPager
+import androidx.compose.foundation.pager.rememberPagerState
+import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.systemui.Flags
+import com.android.systemui.qs.panels.ui.compose.PagerDots
import com.android.systemui.statusbar.policy.ui.dialog.viewmodel.ModesDialogViewModel
@Composable
fun ModeTileGrid(viewModel: ModesDialogViewModel) {
val tiles by viewModel.tiles.collectAsStateWithLifecycle(initialValue = emptyList())
- LazyVerticalGrid(
- columns = GridCells.Fixed(1),
- modifier = Modifier.fillMaxWidth().heightIn(max = 280.dp),
- verticalArrangement = Arrangement.spacedBy(8.dp),
- horizontalArrangement = Arrangement.spacedBy(8.dp),
- ) {
- items(tiles.size, key = { index -> tiles[index].id }) { index ->
- ModeTile(viewModel = tiles[index])
+ if (Flags.modesUiDialogPaging()) {
+ val tilesPerPage = 3
+ val totalPages = { (tiles.size + tilesPerPage - 1) / tilesPerPage }
+ val pagerState = rememberPagerState(initialPage = 0, pageCount = totalPages)
+
+ Column {
+ HorizontalPager(
+ state = pagerState,
+ modifier = Modifier.fillMaxWidth(),
+ pageSpacing = 16.dp,
+ verticalAlignment = Alignment.Top,
+ // Pre-emptively layout and compose the next page, to make sure the height stays
+ // the same even if we have fewer than [tilesPerPage] tiles on the last page.
+ beyondViewportPageCount = 1,
+ ) { page ->
+ Column(
+ modifier = Modifier.fillMaxWidth().fillMaxHeight(),
+ verticalArrangement = Arrangement.spacedBy(8.dp, alignment = Alignment.Top),
+ ) {
+ val startIndex = page * tilesPerPage
+ val endIndex = minOf((page + 1) * tilesPerPage, tiles.size)
+ for (index in startIndex until endIndex) {
+ ModeTile(viewModel = tiles[index], modifier = Modifier.fillMaxWidth())
+ }
+ }
+ }
+
+ PagerDots(
+ pagerState = pagerState,
+ activeColor = MaterialTheme.colorScheme.primary,
+ nonActiveColor = MaterialTheme.colorScheme.onSurfaceVariant,
+ modifier = Modifier.align(Alignment.CenterHorizontally).padding(top = 8.dp),
+ )
+ }
+ } else {
+ LazyVerticalGrid(
+ columns = GridCells.Fixed(1),
+ modifier = Modifier.fillMaxWidth().heightIn(max = 280.dp),
+ verticalArrangement = Arrangement.spacedBy(8.dp),
+ horizontalArrangement = Arrangement.spacedBy(8.dp),
+ ) {
+ items(tiles.size, key = { index -> tiles[index].id }) { index ->
+ ModeTile(viewModel = tiles[index])
+ }
}
}
}
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 57fad83da8b9..6069b4409ec9 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
@@ -610,6 +610,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
@DisableFlags({FooterViewRefactor.FLAG_NAME, NotifRedesignFooter.FLAG_NAME})
+ @DisableSceneContainer
public void testUpdateFooter_remoteInput() {
setBarStateForTest(StatusBarState.SHADE);
mStackScroller.setCurrentUserSetup(true);
@@ -643,6 +644,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
@DisableFlags({FooterViewRefactor.FLAG_NAME, NotifRedesignFooter.FLAG_NAME})
+ @DisableSceneContainer
public void testUpdateFooter_oneClearableNotification() {
setBarStateForTest(StatusBarState.SHADE);
mStackScroller.setCurrentUserSetup(true);
@@ -659,6 +661,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
@DisableFlags({FooterViewRefactor.FLAG_NAME, NotifRedesignFooter.FLAG_NAME})
+ @DisableSceneContainer
public void testUpdateFooter_withoutHistory() {
setBarStateForTest(StatusBarState.SHADE);
mStackScroller.setCurrentUserSetup(true);
@@ -692,6 +695,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
@DisableFlags({FooterViewRefactor.FLAG_NAME, NotifRedesignFooter.FLAG_NAME})
+ @DisableSceneContainer
public void testUpdateFooter_oneNonClearableNotification() {
setBarStateForTest(StatusBarState.SHADE);
mStackScroller.setCurrentUserSetup(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index c4c2aa7934f2..48106de5225b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -2533,6 +2533,42 @@ public class BubblesTest extends SysuiTestCase {
verify(mBubbleLogger).log(BubbleLogger.Event.BUBBLE_BAR_DISMISSED_DRAG_BAR);
}
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @Test
+ public void testEventLogging_bubbleBar_expandAndCollapse() {
+ mBubbleProperties.mIsBubbleBarEnabled = true;
+ mPositioner.setIsLargeScreen(true);
+ FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+ mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+ mEntryListener.onEntryAdded(mRow);
+ mBubbleController.expandStackAndSelectBubbleFromLauncher(mRow.getKey(), 0);
+
+ verify(mBubbleLogger).log(eqBubbleWithKey(mRow.getKey()),
+ eq(BubbleLogger.Event.BUBBLE_BAR_EXPANDED));
+
+ mBubbleController.collapseStack();
+
+ verify(mBubbleLogger).log(eqBubbleWithKey(mRow.getKey()),
+ eq(BubbleLogger.Event.BUBBLE_BAR_COLLAPSED));
+ }
+
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @Test
+ public void testEventLogging_bubbleBar_autoExpandingBubble() {
+ mBubbleProperties.mIsBubbleBarEnabled = true;
+ mPositioner.setIsLargeScreen(true);
+ FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+ mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+ setMetadataFlags(mRow,
+ Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, true /* enableFlag */);
+ mEntryListener.onEntryAdded(mRow);
+
+ verify(mBubbleLogger).log(eqBubbleWithKey(mRow.getKey()),
+ eq(BubbleLogger.Event.BUBBLE_BAR_EXPANDED));
+ }
+
/** Creates a bubble using the userId and package. */
private Bubble createBubble(int userId, String pkg) {
final UserHandle userHandle = new UserHandle(userId);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt
index 62d221dd9790..b27dadc9035b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt
@@ -40,8 +40,18 @@ class FakeCommunalWidgetRepository(private val coroutineScope: CoroutineScope) :
) {
coroutineScope.launch {
val id = nextWidgetId++
- val providerInfo = AppWidgetProviderInfo().apply { this.provider = provider }
- val configured = configurator?.configureWidget(id) ?: true
+ val providerInfo = createAppWidgetProviderInfo(provider, user.identifier)
+
+ fakeDatabase[id] =
+ CommunalWidgetContentModel.Available(
+ appWidgetId = id,
+ rank = rank ?: 0,
+ providerInfo = providerInfo,
+ spanY = 3,
+ )
+ updateListFromDatabase()
+
+ val configured = configurator?.configureWidget(id) != false
if (configured) {
onConfigured(id, providerInfo, rank ?: -1)
}
@@ -61,20 +71,15 @@ class FakeCommunalWidgetRepository(private val coroutineScope: CoroutineScope) :
appWidgetId = appWidgetId,
rank = rank,
providerInfo =
- AppWidgetProviderInfo().apply {
- provider = ComponentName.unflattenFromString(componentName)!!
- widgetCategory = category
- providerInfo =
- ActivityInfo().apply {
- applicationInfo =
- ApplicationInfo().apply {
- uid = userId * UserHandle.PER_USER_RANGE
- }
- }
- },
+ createAppWidgetProviderInfo(
+ ComponentName.unflattenFromString(componentName)!!,
+ userId,
+ category,
+ ),
spanY = spanY,
)
updateListFromDatabase()
+ nextWidgetId = appWidgetId + 1
}
fun addPendingWidget(
@@ -151,4 +156,20 @@ class FakeCommunalWidgetRepository(private val coroutineScope: CoroutineScope) :
)
updateListFromDatabase()
}
+
+ private fun createAppWidgetProviderInfo(
+ componentName: ComponentName,
+ userId: Int,
+ category: Int = AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD,
+ ): AppWidgetProviderInfo {
+ return AppWidgetProviderInfo().apply {
+ provider = componentName
+ widgetCategory = category
+ providerInfo =
+ ActivityInfo().apply {
+ applicationInfo =
+ ApplicationInfo().apply { uid = userId * UserHandle.PER_USER_RANGE }
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
index 629fda6b610c..1f68195a9acc 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
@@ -54,7 +54,6 @@ val Kosmos.communalInteractor by Fixture {
keyguardInteractor = keyguardInteractor,
keyguardTransitionInteractor = keyguardTransitionInteractor,
communalSettingsInteractor = communalSettingsInteractor,
- appWidgetHost = mock(),
editWidgetsActivityStarter = editWidgetsActivityStarter,
userTracker = userTracker,
activityStarter = activityStarter,
@@ -62,7 +61,7 @@ val Kosmos.communalInteractor by Fixture {
sceneInteractor = sceneInteractor,
logBuffer = logcatLogBuffer("CommunalInteractor"),
tableLogBuffer = mock(),
- managedProfileController = fakeManagedProfileController
+ managedProfileController = fakeManagedProfileController,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/shared/model/FakeGlanceableHubMultiUserHelper.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/shared/model/FakeGlanceableHubMultiUserHelper.kt
new file mode 100644
index 000000000000..de44399b4a5b
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/shared/model/FakeGlanceableHubMultiUserHelper.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.systemui.communal.shared.model
+
+class FakeGlanceableHubMultiUserHelper(
+ override val glanceableHubHsumFlagEnabled: Boolean = true,
+ private var isHeadlessSystemUserMode: Boolean = false,
+ private var isInHeadlessSystemUser: Boolean = false,
+) : GlanceableHubMultiUserHelper {
+
+ override fun isHeadlessSystemUserMode(): Boolean {
+ return isHeadlessSystemUserMode
+ }
+
+ fun setIsHeadlessSystemUserMode(isHeadlessSystemUserMode: Boolean) {
+ this.isHeadlessSystemUserMode = isHeadlessSystemUserMode
+ }
+
+ override fun isInHeadlessSystemUser(): Boolean {
+ return isInHeadlessSystemUser
+ }
+
+ fun setIsInHeadlessSystemUser(isInHeadlessSystemUser: Boolean) {
+ this.isInHeadlessSystemUser = isInHeadlessSystemUser
+ }
+
+ override fun assertInHeadlessSystemUser() {
+ check(isInHeadlessSystemUser())
+ }
+
+ override fun assertNotInHeadlessSystemUser() {
+ check(!isInHeadlessSystemUser())
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/shared/model/GlanceableHubMultiUserHelperKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/shared/model/GlanceableHubMultiUserHelperKosmos.kt
new file mode 100644
index 000000000000..adee44074e51
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/shared/model/GlanceableHubMultiUserHelperKosmos.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.shared.model
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.fakeGlanceableHubMultiUserHelper by Kosmos.Fixture { FakeGlanceableHubMultiUserHelper() }
+
+val Kosmos.glanceableHubMultiUserHelper by
+ Kosmos.Fixture<GlanceableHubMultiUserHelper> { fakeGlanceableHubMultiUserHelper }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerKosmos.kt
new file mode 100644
index 000000000000..583ae443c95f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.widgets
+
+import com.android.systemui.kosmos.Kosmos
+import org.mockito.kotlin.mock
+
+val Kosmos.mockGlanceableHubWidgetManager by Kosmos.Fixture<GlanceableHubWidgetManager> { mock() }
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index 866359399128..44ea9a2848ac 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -945,10 +945,11 @@ public class WallpaperBackupAgent extends BackupAgent {
String tag = parser.getName();
if (!sectionTag.equals(tag)) continue;
for (Pair<Integer, String> pair : List.of(
- new Pair<>(WallpaperManager.PORTRAIT, "Portrait"),
- new Pair<>(WallpaperManager.LANDSCAPE, "Landscape"),
- new Pair<>(WallpaperManager.SQUARE_PORTRAIT, "SquarePortrait"),
- new Pair<>(WallpaperManager.SQUARE_LANDSCAPE, "SquareLandscape"))) {
+ new Pair<>(WallpaperManager.ORIENTATION_PORTRAIT, "Portrait"),
+ new Pair<>(WallpaperManager.ORIENTATION_LANDSCAPE, "Landscape"),
+ new Pair<>(WallpaperManager.ORIENTATION_SQUARE_PORTRAIT, "SquarePortrait"),
+ new Pair<>(WallpaperManager.ORIENTATION_SQUARE_LANDSCAPE,
+ "SquareLandscape"))) {
Rect cropHint = new Rect(
getAttributeInt(parser, "cropLeft" + pair.second, 0),
getAttributeInt(parser, "cropTop" + pair.second, 0),
diff --git a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
index 3ecdf3f101a5..f5fb644502ab 100644
--- a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
+++ b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
@@ -827,16 +827,17 @@ public class WallpaperBackupAgentTest {
@Test
public void testOnRestore_singleCropHint() throws Exception {
- Map<Integer, Rect> testMap = Map.of(WallpaperManager.PORTRAIT, new Rect(1, 2, 3, 4));
+ Map<Integer, Rect> testMap = Map.of(
+ WallpaperManager.ORIENTATION_PORTRAIT, new Rect(1, 2, 3, 4));
testParseCropHints(testMap);
}
@Test
public void testOnRestore_multipleCropHints() throws Exception {
Map<Integer, Rect> testMap = Map.of(
- WallpaperManager.PORTRAIT, new Rect(1, 2, 3, 4),
- WallpaperManager.SQUARE_PORTRAIT, new Rect(5, 6, 7, 8),
- WallpaperManager.SQUARE_LANDSCAPE, new Rect(9, 10, 11, 12));
+ WallpaperManager.ORIENTATION_PORTRAIT, new Rect(1, 2, 3, 4),
+ WallpaperManager.ORIENTATION_SQUARE_PORTRAIT, new Rect(5, 6, 7, 8),
+ WallpaperManager.ORIENTATION_SQUARE_LANDSCAPE, new Rect(9, 10, 11, 12));
testParseCropHints(testMap);
}
@@ -936,10 +937,10 @@ public class WallpaperBackupAgentTest {
out.startTag(null, "wp");
for (Map.Entry<Integer, Rect> entry: crops.entrySet()) {
String orientation = switch (entry.getKey()) {
- case WallpaperManager.PORTRAIT -> "Portrait";
- case WallpaperManager.LANDSCAPE -> "Landscape";
- case WallpaperManager.SQUARE_PORTRAIT -> "SquarePortrait";
- case WallpaperManager.SQUARE_LANDSCAPE -> "SquareLandscape";
+ case WallpaperManager.ORIENTATION_PORTRAIT -> "Portrait";
+ case WallpaperManager.ORIENTATION_LANDSCAPE -> "Landscape";
+ case WallpaperManager.ORIENTATION_SQUARE_PORTRAIT -> "SquarePortrait";
+ case WallpaperManager.ORIENTATION_SQUARE_LANDSCAPE -> "SquareLandscape";
default -> throw new IllegalArgumentException("Invalid orientation");
};
Rect rect = entry.getValue();
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
index 89f14b09d397..268e56487c4b 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
@@ -86,7 +86,6 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
private final Context mContext;
private final Map<String, Object> mLocks = new WeakHashMap<>();
-
public AppFunctionManagerServiceImpl(@NonNull Context context) {
this(
context,
@@ -201,7 +200,7 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
if (mCallerValidator.isUserOrganizationManaged(targetUser)) {
safeExecuteAppFunctionCallback.onResult(
ExecuteAppFunctionResponse.newFailure(
- ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR,
+ ExecuteAppFunctionResponse.RESULT_SYSTEM_ERROR,
"Cannot run on a device with a device owner or from the managed"
+ " profile.",
/* extras= */ null));
@@ -256,7 +255,7 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
if (serviceIntent == null) {
safeExecuteAppFunctionCallback.onResult(
ExecuteAppFunctionResponse.newFailure(
- ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR,
+ ExecuteAppFunctionResponse.RESULT_SYSTEM_ERROR,
"Cannot find the target service.",
/* extras= */ null));
return;
@@ -449,7 +448,7 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
Slog.e(TAG, "Failed to bind to the AppFunctionService");
safeExecuteAppFunctionCallback.onResult(
ExecuteAppFunctionResponse.newFailure(
- ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR,
+ ExecuteAppFunctionResponse.RESULT_SYSTEM_ERROR,
"Failed to bind the AppFunctionService.",
/* extras= */ null));
}
@@ -464,7 +463,7 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
if (e instanceof CompletionException) {
e = e.getCause();
}
- int resultCode = ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR;
+ int resultCode = ExecuteAppFunctionResponse.RESULT_SYSTEM_ERROR;
if (e instanceof AppSearchException appSearchException) {
resultCode =
mapAppSearchResultFailureCodeToExecuteAppFunctionResponse(
@@ -486,13 +485,13 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
switch (resultCode) {
case AppSearchResult.RESULT_NOT_FOUND:
- return ExecuteAppFunctionResponse.RESULT_INVALID_ARGUMENT;
+ return ExecuteAppFunctionResponse.RESULT_FUNCTION_NOT_FOUND;
case AppSearchResult.RESULT_INVALID_ARGUMENT:
case AppSearchResult.RESULT_INTERNAL_ERROR:
case AppSearchResult.RESULT_SECURITY_ERROR:
// fall-through
}
- return ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR;
+ return ExecuteAppFunctionResponse.RESULT_SYSTEM_ERROR;
}
private void registerAppSearchObserver(@NonNull TargetUser user) {
@@ -543,12 +542,13 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
});
}
}
+
/**
* Retrieves the lock object associated with the given package name.
*
- * This method returns the lock object from the {@code mLocks} map if it exists.
- * If no lock is found for the given package name, a new lock object is created,
- * stored in the map, and returned.
+ * <p>This method returns the lock object from the {@code mLocks} map if it exists. If no lock
+ * is found for the given package name, a new lock object is created, stored in the map, and
+ * returned.
*/
@VisibleForTesting
@NonNull
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index f9abd8558ca8..68ff9725ce5c 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -1469,9 +1469,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
mSecurityPolicy.enforceCallFromPackage(callingPackage);
// Check that if a cross-profile binding is attempted, it is allowed.
- // Cross-profile binding is also allowed if the caller has interact across users permission.
- if (!mSecurityPolicy.isEnabledGroupProfile(providerProfileId)
- && !mSecurityPolicy.hasCallerInteractAcrossUsersPermission()) {
+ if (!mSecurityPolicy.isEnabledGroupProfile(providerProfileId)) {
return false;
}
@@ -2440,10 +2438,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
Slog.i(TAG, "getInstalledProvidersForProfiles() " + userId);
}
- // Ensure the profile is in the group and enabled, or that the caller has permission to
- // interact across users.
- if (!mSecurityPolicy.isEnabledGroupProfile(profileId)
- && !mSecurityPolicy.hasCallerInteractAcrossUsersPermission()) {
+ // Ensure the profile is in the group and enabled.
+ if (!mSecurityPolicy.isEnabledGroupProfile(profileId)) {
return null;
}
@@ -5235,11 +5231,14 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
return true;
}
final int userId = UserHandle.getUserId(uid);
- if ((widget.host.getUserId() == userId || (widget.provider != null
- && widget.provider.getUserId() == userId))
+ if ((widget.host.getUserId() == userId
+ || (widget.provider != null && widget.provider.getUserId() == userId)
+ || hasCallerInteractAcrossUsersPermission())
&& callerHasPermission(android.Manifest.permission.BIND_APPWIDGET)) {
- // Apps that run in the same user as either the host or the provider and
- // have the bind widget permission have access to the widget.
+ // Access to the widget requires the app to:
+ // - Run in the same user as the host or provider, or have permission to interact
+ // across users
+ // - Have bind widget permission
return true;
}
if (DEBUG) {
@@ -5260,16 +5259,12 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
* The provider is accessible by the caller if any of the following is true:
* - The provider belongs to the caller
* - The provider belongs to a profile of the caller and is allowlisted
- * - The caller has permission to interact across users
*/
public boolean canAccessProvider(String packageName, int profileId) {
final int callerId = UserHandle.getCallingUserId();
if (profileId == callerId) {
return true;
}
- if (hasCallerInteractAcrossUsersPermission()) {
- return true;
- }
final int parentId = getProfileParent(profileId);
if (parentId != callerId) {
return false;
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 363807d2aa8c..72a9a2d6de26 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -102,6 +102,7 @@ import com.android.internal.telephony.ICarrierConfigChangeListener;
import com.android.internal.telephony.ICarrierPrivilegesCallback;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
import com.android.internal.telephony.IPhoneStateListener;
+import com.android.internal.telephony.ISatelliteStateChangeListener;
import com.android.internal.telephony.ITelephonyRegistry;
import com.android.internal.telephony.TelephonyPermissions;
import com.android.internal.telephony.flags.Flags;
@@ -126,6 +127,7 @@ import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
/**
@@ -164,6 +166,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
IOnSubscriptionsChangedListener onOpportunisticSubscriptionsChangedListenerCallback;
ICarrierPrivilegesCallback carrierPrivilegesCallback;
ICarrierConfigChangeListener carrierConfigChangeListener;
+ ISatelliteStateChangeListener satelliteStateChangeListener;
int callerUid;
int callerPid;
@@ -196,6 +199,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
return carrierConfigChangeListener != null;
}
+ boolean matchSatelliteStateChangeListener() {
+ return satelliteStateChangeListener != null;
+ }
+
boolean canReadCallLog() {
try {
return TelephonyPermissions.checkReadCallLog(
@@ -215,6 +222,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
+ onOpportunisticSubscriptionsChangedListenerCallback
+ " carrierPrivilegesCallback=" + carrierPrivilegesCallback
+ " carrierConfigChangeListener=" + carrierConfigChangeListener
+ + " satelliteStateChangeListener=" + satelliteStateChangeListener
+ " subId=" + subId + " phoneId=" + phoneId + " events=" + eventList + "}";
}
}
@@ -433,6 +441,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private List<IntArray> mCarrierRoamingNtnAvailableServices;
+ // Local cache to check if Satellite Modem is enabled
+ private AtomicBoolean mIsSatelliteEnabled;
+ private AtomicBoolean mWasSatelliteEnabledNotified;
+
/**
* Per-phone map of precise data connection state. The key of the map is the pair of transport
* type and APN setting. This is the cache to prevent redundant callbacks to the listeners.
@@ -871,6 +883,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mCarrierRoamingNtnMode = new boolean[numPhones];
mCarrierRoamingNtnEligible = new boolean[numPhones];
mCarrierRoamingNtnAvailableServices = new ArrayList<>();
+ mIsSatelliteEnabled = new AtomicBoolean();
+ mWasSatelliteEnabledNotified = new AtomicBoolean();
+
for (int i = 0; i < numPhones; i++) {
mCallState[i] = TelephonyManager.CALL_STATE_IDLE;
@@ -3425,6 +3440,94 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
@Override
+ public void addSatelliteStateChangeListener(@NonNull ISatelliteStateChangeListener listener,
+ @NonNull String pkg, @Nullable String featureId) {
+ final int callerUserId = UserHandle.getCallingUserId();
+ mAppOps.checkPackage(Binder.getCallingUid(), pkg);
+ enforceCallingOrSelfAtLeastReadBasicPhoneStatePermission(pkg, featureId,
+ "addSatelliteStateChangeListener");
+ if (VDBG) {
+ log("addSatelliteStateChangeListener pkg=" + pii(pkg)
+ + " uid=" + Binder.getCallingUid()
+ + " myUserId=" + UserHandle.myUserId() + " callerUerId" + callerUserId
+ + " listener=" + listener + " listener.asBinder=" + listener.asBinder());
+ }
+
+ synchronized (mRecords) {
+ final IBinder b = listener.asBinder();
+ boolean doesLimitApply = doesLimitApplyForListeners(Binder.getCallingUid(),
+ Process.myUid());
+ Record r = add(b, Binder.getCallingUid(), Binder.getCallingPid(), doesLimitApply);
+
+ if (r == null) {
+ loge("addSatelliteStateChangeListener: can not create Record instance!");
+ return;
+ }
+
+ r.context = mContext;
+ r.satelliteStateChangeListener = listener;
+ r.callingPackage = pkg;
+ r.callingFeatureId = featureId;
+ r.callerUid = Binder.getCallingUid();
+ r.callerPid = Binder.getCallingPid();
+ r.eventList = new ArraySet<>();
+ if (DBG) {
+ log("addSatelliteStateChangeListener: Register r=" + r);
+ }
+
+ // Always notify registrants on registration if it has been notified before
+ if (mWasSatelliteEnabledNotified.get() && r.matchSatelliteStateChangeListener()) {
+ try {
+ r.satelliteStateChangeListener.onSatelliteEnabledStateChanged(
+ mIsSatelliteEnabled.get());
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void removeSatelliteStateChangeListener(@NonNull ISatelliteStateChangeListener listener,
+ @NonNull String pkg) {
+ if (DBG) log("removeSatelliteStateChangeListener listener=" + listener + ", pkg=" + pkg);
+ mAppOps.checkPackage(Binder.getCallingUid(), pkg);
+ enforceCallingOrSelfAtLeastReadBasicPhoneStatePermission(pkg, null,
+ "removeSatelliteStateChangeListener");
+ remove(listener.asBinder());
+ }
+
+ @Override
+ public void notifySatelliteStateChanged(boolean isEnabled) {
+ if (!checkNotifyPermission("notifySatelliteStateChanged")) {
+ loge("notifySatelliteStateChanged: Caller has no notify permission!");
+ return;
+ }
+ if (VDBG) {
+ log("notifySatelliteStateChanged: isEnabled=" + isEnabled);
+ }
+
+ mWasSatelliteEnabledNotified.set(true);
+ mIsSatelliteEnabled.set(isEnabled);
+
+ synchronized (mRecords) {
+ mRemoveList.clear();
+ for (Record r : mRecords) {
+ // Listeners are "global", neither per-slot nor per-sub, so no idMatch check here
+ if (!r.matchSatelliteStateChangeListener()) {
+ continue;
+ }
+ try {
+ r.satelliteStateChangeListener.onSatelliteEnabledStateChanged(isEnabled);
+ } catch (RemoteException re) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ handleRemoveListLocked();
+ }
+ }
+
+ @Override
public void notifyMediaQualityStatusChanged(int phoneId, int subId, MediaQualityStatus status) {
if (!checkNotifyPermission("notifyMediaQualityStatusChanged()")) {
return;
@@ -4622,4 +4725,32 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (packageNames.isEmpty() || Build.IS_DEBUGGABLE) return packageNames.toString();
return "[***, size=" + packageNames.size() + "]";
}
+
+ /**
+ * The method enforces the calling package at least has READ_BASIC_PHONE_STATE permission.
+ * That is, calling package either has READ_PRIVILEGED_PHONE_STATE, READ_PHONE_STATE or Carrier
+ * Privileges on ANY active subscription, or has READ_BASIC_PHONE_STATE permission.
+ */
+ private void enforceCallingOrSelfAtLeastReadBasicPhoneStatePermission(String pkgName,
+ String featureId, String message) {
+ // Check if calling app has READ_PHONE_STATE on ANY active subscription
+ boolean hasReadPhoneState = false;
+ SubscriptionManager sm = mContext.getSystemService(SubscriptionManager.class);
+ if (sm != null) {
+ for (int subId : sm.getActiveSubscriptionIdList()) {
+ if (TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow(mContext, subId,
+ pkgName, featureId, message)) {
+ hasReadPhoneState = true;
+ break;
+ }
+ }
+ }
+
+ // If yes, pass. If not, then enforce READ_BASIC_PHONE_STATE permission
+ if (!hasReadPhoneState) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.READ_BASIC_PHONE_STATE,
+ message);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
index 61079fc78f8a..c1d55971bdce 100644
--- a/services/core/java/com/android/server/am/OWNERS
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -49,6 +49,7 @@ per-file User* = file:/MULTIUSER_OWNERS
# Broadcasts
per-file Broadcast* = file:/BROADCASTS_OWNERS
+per-file broadcasts_flags.aconfig = file:/BROADCASTS_OWNERS
# Permissions & Packages
per-file *Permission* = patb@google.com
diff --git a/services/core/java/com/android/server/am/broadcasts_flags.aconfig b/services/core/java/com/android/server/am/broadcasts_flags.aconfig
new file mode 100644
index 000000000000..b1185d552941
--- /dev/null
+++ b/services/core/java/com/android/server/am/broadcasts_flags.aconfig
@@ -0,0 +1,10 @@
+package: "com.android.server.am"
+container: "system"
+
+flag {
+ name: "restrict_priority_values"
+ namespace: "backstage_power"
+ description: "Restrict priority values defined by non-system apps"
+ is_fixed_read_only: true
+ bug: "369487976"
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index 883482053490..56cfdfb7edde 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -235,14 +235,6 @@ flag {
}
flag {
- name: "restrict_priority_values"
- namespace: "backstage_power"
- description: "Restrict priority values defined by non-system apps"
- is_fixed_read_only: true
- bug: "369487976"
-}
-
-flag {
name: "unfreeze_bind_policy_fix"
namespace: "backstage_power"
description: "Make sure shouldNotFreeze state change correctly triggers updates."
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index 1604e94e5a6d..1da62d74f0df 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -1068,7 +1068,6 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
switch (attr.getUsage()) {
case AudioAttributes.USAGE_MEDIA:
case AudioAttributes.USAGE_GAME:
- case AudioAttributes.USAGE_SPEAKER_CLEANUP:
return 1000;
case AudioAttributes.USAGE_ALARM:
case AudioAttributes.USAGE_NOTIFICATION_RINGTONE:
diff --git a/services/core/java/com/android/server/input/InputGestureManager.java b/services/core/java/com/android/server/input/InputGestureManager.java
index ae31b33f8c20..f4bd402e63a2 100644
--- a/services/core/java/com/android/server/input/InputGestureManager.java
+++ b/services/core/java/com/android/server/input/InputGestureManager.java
@@ -17,10 +17,13 @@
package com.android.server.input;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.hardware.input.InputGestureData;
import android.hardware.input.InputManager;
import android.util.IndentingPrintWriter;
import android.util.SparseArray;
+import android.view.KeyEvent;
import com.android.internal.annotations.GuardedBy;
@@ -40,6 +43,10 @@ import java.util.Objects;
final class InputGestureManager {
private static final String TAG = "InputGestureManager";
+ private static final int KEY_GESTURE_META_MASK =
+ KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON
+ | KeyEvent.META_META_ON;
+
@GuardedBy("mCustomInputGestures")
private final SparseArray<Map<InputGestureData.Trigger, InputGestureData>>
mCustomInputGestures = new SparseArray<>();
@@ -96,6 +103,23 @@ final class InputGestureManager {
}
}
+ @Nullable
+ public InputGestureData getCustomGestureForKeyEvent(@UserIdInt int userId, KeyEvent event) {
+ final int keyCode = event.getKeyCode();
+ if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
+ return null;
+ }
+ synchronized (mCustomInputGestures) {
+ Map<InputGestureData.Trigger, InputGestureData> customGestures =
+ mCustomInputGestures.get(userId);
+ if (customGestures == null) {
+ return null;
+ }
+ int modifierState = event.getMetaState() & KEY_GESTURE_META_MASK;
+ return customGestures.get(InputGestureData.createKeyTrigger(keyCode, modifierState));
+ }
+ }
+
public void dump(IndentingPrintWriter ipw) {
ipw.println("InputGestureManager:");
ipw.increaseIndent();
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index d43ce71898d3..26929f5999eb 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -3022,6 +3022,7 @@ public class InputManagerService extends IInputManager.Stub
private void handleCurrentUserChanged(@UserIdInt int userId) {
mCurrentUserId = userId;
+ mKeyGestureController.setCurrentUserId(userId);
}
/**
diff --git a/services/core/java/com/android/server/input/KeyGestureController.java b/services/core/java/com/android/server/input/KeyGestureController.java
index e665f96ab282..ebeef651c19b 100644
--- a/services/core/java/com/android/server/input/KeyGestureController.java
+++ b/services/core/java/com/android/server/input/KeyGestureController.java
@@ -40,6 +40,7 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.input.AidlInputGestureData;
import android.hardware.input.AidlKeyGestureEvent;
+import android.hardware.input.AppLaunchData;
import android.hardware.input.IKeyGestureEventListener;
import android.hardware.input.IKeyGestureHandler;
import android.hardware.input.InputGestureData;
@@ -91,6 +92,9 @@ final class KeyGestureController {
// Maximum key gesture events that are tracked and will be available in input dump.
private static final int MAX_TRACKED_EVENTS = 10;
+ private static final int SHORTCUT_META_MASK =
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON
+ | KeyEvent.META_SHIFT_ON;
private static final int MSG_NOTIFY_KEY_GESTURE_EVENT = 1;
@@ -116,6 +120,10 @@ final class KeyGestureController {
private final KeyCombinationManager mKeyCombinationManager;
private final SettingsObserver mSettingsObserver;
private final InputGestureManager mInputGestureManager = new InputGestureManager();
+ private static final Object mUserLock = new Object();
+ @UserIdInt
+ @GuardedBy("mUserLock")
+ private int mCurrentUserId = UserHandle.USER_SYSTEM;
// Pending actions
private boolean mPendingMetaAction;
@@ -229,7 +237,7 @@ final class KeyGestureController {
@Override
public void execute() {
- handleKeyGesture(
+ handleMultiKeyGesture(
new int[]{KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_POWER},
KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD,
KeyGestureEvent.ACTION_GESTURE_START, 0);
@@ -237,7 +245,7 @@ final class KeyGestureController {
@Override
public void cancel() {
- handleKeyGesture(
+ handleMultiKeyGesture(
new int[]{KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_POWER},
KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD,
KeyGestureEvent.ACTION_GESTURE_COMPLETE,
@@ -257,14 +265,14 @@ final class KeyGestureController {
@Override
public void execute() {
- handleKeyGesture(new int[]{KeyEvent.KEYCODE_POWER,
+ handleMultiKeyGesture(new int[]{KeyEvent.KEYCODE_POWER,
KeyEvent.KEYCODE_STEM_PRIMARY},
KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD,
KeyGestureEvent.ACTION_GESTURE_START, 0);
}
@Override
public void cancel() {
- handleKeyGesture(new int[]{KeyEvent.KEYCODE_POWER,
+ handleMultiKeyGesture(new int[]{KeyEvent.KEYCODE_POWER,
KeyEvent.KEYCODE_STEM_PRIMARY},
KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD,
KeyGestureEvent.ACTION_GESTURE_COMPLETE,
@@ -285,7 +293,7 @@ final class KeyGestureController {
@Override
public void execute() {
- handleKeyGesture(
+ handleMultiKeyGesture(
new int[]{KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_UP},
KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD,
KeyGestureEvent.ACTION_GESTURE_START, 0);
@@ -293,7 +301,7 @@ final class KeyGestureController {
@Override
public void cancel() {
- handleKeyGesture(
+ handleMultiKeyGesture(
new int[]{KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_UP},
KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD,
KeyGestureEvent.ACTION_GESTURE_COMPLETE,
@@ -325,7 +333,7 @@ final class KeyGestureController {
if (gestureType == KeyGestureEvent.KEY_GESTURE_TYPE_UNSPECIFIED) {
return;
}
- handleKeyGesture(
+ handleMultiKeyGesture(
new int[]{KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_POWER},
gestureType, KeyGestureEvent.ACTION_GESTURE_START, 0);
}
@@ -335,7 +343,7 @@ final class KeyGestureController {
if (gestureType == KeyGestureEvent.KEY_GESTURE_TYPE_UNSPECIFIED) {
return;
}
- handleKeyGesture(
+ handleMultiKeyGesture(
new int[]{KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_POWER},
gestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE,
KeyGestureEvent.FLAG_CANCELLED);
@@ -369,7 +377,7 @@ final class KeyGestureController {
@Override
public void execute() {
- handleKeyGesture(
+ handleMultiKeyGesture(
new int[]{KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN},
KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD,
KeyGestureEvent.ACTION_GESTURE_START, 0);
@@ -377,7 +385,7 @@ final class KeyGestureController {
@Override
public void cancel() {
- handleKeyGesture(
+ handleMultiKeyGesture(
new int[]{KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN},
KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD,
KeyGestureEvent.ACTION_GESTURE_COMPLETE,
@@ -406,14 +414,14 @@ final class KeyGestureController {
@Override
public void execute() {
- handleKeyGesture(
+ handleMultiKeyGesture(
new int[]{KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_CENTER},
KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT,
KeyGestureEvent.ACTION_GESTURE_START, 0);
}
@Override
public void cancel() {
- handleKeyGesture(
+ handleMultiKeyGesture(
new int[]{KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_CENTER},
KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT,
KeyGestureEvent.ACTION_GESTURE_COMPLETE,
@@ -488,7 +496,7 @@ final class KeyGestureController {
private boolean interceptSystemKeysAndShortcuts(IBinder focusedToken, KeyEvent event) {
final int keyCode = event.getKeyCode();
final int repeatCount = event.getRepeatCount();
- final int metaState = event.getMetaState();
+ final int metaState = event.getMetaState() & SHORTCUT_META_MASK;
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
final int displayId = event.getDisplayId();
@@ -511,7 +519,7 @@ final class KeyGestureController {
return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
break;
case KeyEvent.KEYCODE_RECENT_APPS:
@@ -519,7 +527,7 @@ final class KeyGestureController {
handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
return true;
case KeyEvent.KEYCODE_APP_SWITCH:
@@ -527,12 +535,13 @@ final class KeyGestureController {
handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH,
KeyGestureEvent.ACTION_GESTURE_START, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
} else if (!down) {
handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, canceled ? KeyGestureEvent.FLAG_CANCELLED : 0);
+ focusedToken, canceled ? KeyGestureEvent.FLAG_CANCELLED : 0,
+ /* appLaunchData = */null);
}
return true;
case KeyEvent.KEYCODE_H:
@@ -541,7 +550,7 @@ final class KeyGestureController {
return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_HOME,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
break;
case KeyEvent.KEYCODE_I:
@@ -549,7 +558,7 @@ final class KeyGestureController {
return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
break;
case KeyEvent.KEYCODE_L:
@@ -557,7 +566,7 @@ final class KeyGestureController {
return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
break;
case KeyEvent.KEYCODE_N:
@@ -567,13 +576,13 @@ final class KeyGestureController {
KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
} else {
return handleKeyGesture(deviceId, new int[]{keyCode},
KeyEvent.META_META_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
}
break;
@@ -583,7 +592,7 @@ final class KeyGestureController {
KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
break;
case KeyEvent.KEYCODE_T:
@@ -593,7 +602,7 @@ final class KeyGestureController {
KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
}
break;
@@ -605,7 +614,7 @@ final class KeyGestureController {
KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
}
break;
@@ -617,7 +626,7 @@ final class KeyGestureController {
KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
}
break;
@@ -629,7 +638,7 @@ final class KeyGestureController {
KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
}
break;
@@ -641,7 +650,7 @@ final class KeyGestureController {
KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
}
break;
@@ -653,7 +662,7 @@ final class KeyGestureController {
KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
}
// fall through
@@ -662,7 +671,7 @@ final class KeyGestureController {
return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_BACK,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
break;
case KeyEvent.KEYCODE_DPAD_UP:
@@ -671,7 +680,7 @@ final class KeyGestureController {
KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
@@ -680,7 +689,7 @@ final class KeyGestureController {
KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_DESKTOP_MODE,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
@@ -690,19 +699,19 @@ final class KeyGestureController {
KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
} else if (event.isAltPressed()) {
return handleKeyGesture(deviceId, new int[]{keyCode},
KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
} else {
return handleKeyGesture(deviceId, new int[]{keyCode},
KeyEvent.META_META_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_BACK,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
}
break;
@@ -713,13 +722,13 @@ final class KeyGestureController {
KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
} else if (event.isAltPressed()) {
return handleKeyGesture(deviceId, new int[]{keyCode},
KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
}
break;
@@ -730,8 +739,7 @@ final class KeyGestureController {
KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY,
KeyGestureEvent.ACTION_GESTURE_COMPLETE,
- displayId,
- focusedToken, /* flags = */0);
+ displayId, focusedToken, /* flags = */0, /* appLaunchData = */null);
}
}
break;
@@ -742,8 +750,7 @@ final class KeyGestureController {
KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW,
KeyGestureEvent.ACTION_GESTURE_COMPLETE,
- displayId,
- focusedToken, /* flags = */0);
+ displayId, focusedToken, /* flags = */0, /* appLaunchData = */null);
}
}
break;
@@ -754,8 +761,7 @@ final class KeyGestureController {
KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
KeyGestureEvent.ACTION_GESTURE_COMPLETE,
- displayId,
- focusedToken, /* flags = */0);
+ displayId, focusedToken, /* flags = */0, /* appLaunchData = */null);
}
}
break;
@@ -766,8 +772,7 @@ final class KeyGestureController {
KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW,
KeyGestureEvent.ACTION_GESTURE_COMPLETE,
- displayId,
- focusedToken, /* flags = */0);
+ displayId, focusedToken, /* flags = */0, /* appLaunchData = */null);
}
}
break;
@@ -778,8 +783,7 @@ final class KeyGestureController {
KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE,
KeyGestureEvent.ACTION_GESTURE_COMPLETE,
- displayId,
- focusedToken, /* flags = */0);
+ displayId, focusedToken, /* flags = */0, /* appLaunchData = */null);
}
}
break;
@@ -788,7 +792,7 @@ final class KeyGestureController {
return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
break;
case KeyEvent.KEYCODE_BRIGHTNESS_UP:
@@ -799,7 +803,7 @@ final class KeyGestureController {
? KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_UP
: KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_DOWN,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
return true;
case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN:
@@ -807,7 +811,7 @@ final class KeyGestureController {
handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
return true;
case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP:
@@ -815,7 +819,7 @@ final class KeyGestureController {
handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
return true;
case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE:
@@ -824,7 +828,7 @@ final class KeyGestureController {
handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
return true;
case KeyEvent.KEYCODE_ALL_APPS:
@@ -832,7 +836,7 @@ final class KeyGestureController {
handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
return true;
case KeyEvent.KEYCODE_NOTIFICATION:
@@ -840,7 +844,7 @@ final class KeyGestureController {
handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
return true;
case KeyEvent.KEYCODE_SEARCH:
@@ -848,7 +852,7 @@ final class KeyGestureController {
return handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SEARCH,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
break;
@@ -859,13 +863,13 @@ final class KeyGestureController {
new int[]{keyCode}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
} else if (mSettingsKeyBehavior == SETTINGS_KEY_BEHAVIOR_NOTIFICATION_PANEL) {
handleKeyGesture(deviceId,
new int[]{keyCode}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
}
return true;
@@ -875,7 +879,7 @@ final class KeyGestureController {
event.isShiftPressed() ? KeyEvent.META_SHIFT_ON : 0,
KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
return true;
case KeyEvent.KEYCODE_CAPS_LOCK:
@@ -885,7 +889,8 @@ final class KeyGestureController {
AidlKeyGestureEvent eventToNotify = createKeyGestureEvent(deviceId,
new int[]{keyCode}, metaState,
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, /* flags = */0);
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, /* flags = */0,
+ /* appLaunchData = */null);
Message msg = Message.obtain(mHandler, MSG_NOTIFY_KEY_GESTURE_EVENT,
eventToNotify);
mHandler.sendMessage(msg);
@@ -896,7 +901,7 @@ final class KeyGestureController {
handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
return true;
case KeyEvent.KEYCODE_META_LEFT:
@@ -917,7 +922,7 @@ final class KeyGestureController {
KeyEvent.KEYCODE_ALT_LEFT}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
} else if (mPendingMetaAction) {
mPendingMetaAction = false;
@@ -926,7 +931,7 @@ final class KeyGestureController {
/* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
}
}
@@ -937,7 +942,7 @@ final class KeyGestureController {
return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
} else if (!mPendingHideRecentSwitcher) {
final int shiftlessModifiers =
event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
@@ -948,7 +953,7 @@ final class KeyGestureController {
KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER,
KeyGestureEvent.ACTION_GESTURE_START, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
}
}
@@ -969,7 +974,7 @@ final class KeyGestureController {
KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
// Toggle Caps Lock on META-ALT.
@@ -979,7 +984,7 @@ final class KeyGestureController {
KeyEvent.KEYCODE_ALT_LEFT}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
}
break;
@@ -998,6 +1003,22 @@ final class KeyGestureController {
+ " interceptKeyBeforeQueueing");
return true;
}
+
+ if (firstDown) {
+ InputGestureData customGesture;
+ synchronized (mUserLock) {
+ customGesture = mInputGestureManager.getCustomGestureForKeyEvent(mCurrentUserId,
+ event);
+ }
+ if (customGesture == null) {
+ return false;
+ }
+ return handleKeyGesture(deviceId, new int[]{keyCode}, metaState,
+ customGesture.getAction().keyGestureType(),
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE,
+ displayId, focusedToken, /* flags = */0,
+ customGesture.getAction().appLaunchData());
+ }
return false;
}
@@ -1020,7 +1041,7 @@ final class KeyGestureController {
? KeyEvent.META_SHIFT_ON : 0),
KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
}
break;
@@ -1032,7 +1053,7 @@ final class KeyGestureController {
KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
break;
case KeyEvent.KEYCODE_SYSRQ:
@@ -1040,7 +1061,7 @@ final class KeyGestureController {
return handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
break;
case KeyEvent.KEYCODE_ESCAPE:
@@ -1048,7 +1069,7 @@ final class KeyGestureController {
return handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0);
+ focusedToken, /* flags = */0, /* appLaunchData = */null);
}
break;
}
@@ -1056,18 +1077,19 @@ final class KeyGestureController {
return false;
}
- private boolean handleKeyGesture(int[] keycodes,
+ private void handleMultiKeyGesture(int[] keycodes,
@KeyGestureEvent.KeyGestureType int gestureType, int action, int flags) {
- return handleKeyGesture(KeyCharacterMap.VIRTUAL_KEYBOARD, keycodes, /* modifierState= */0,
- gestureType, action, Display.DEFAULT_DISPLAY, /* focusedToken = */null, flags);
+ handleKeyGesture(KeyCharacterMap.VIRTUAL_KEYBOARD, keycodes, /* modifierState= */0,
+ gestureType, action, Display.DEFAULT_DISPLAY, /* focusedToken = */null, flags,
+ /* appLaunchData = */null);
}
@VisibleForTesting
boolean handleKeyGesture(int deviceId, int[] keycodes, int modifierState,
@KeyGestureEvent.KeyGestureType int gestureType, int action, int displayId,
- @Nullable IBinder focusedToken, int flags) {
+ @Nullable IBinder focusedToken, int flags, @Nullable AppLaunchData appLaunchData) {
return handleKeyGesture(createKeyGestureEvent(deviceId, keycodes,
- modifierState, gestureType, action, displayId, flags), focusedToken);
+ modifierState, gestureType, action, displayId, flags, appLaunchData), focusedToken);
}
private boolean handleKeyGesture(AidlKeyGestureEvent event, @Nullable IBinder focusedToken) {
@@ -1099,18 +1121,27 @@ final class KeyGestureController {
// TODO(b/358569822): Once we move the gesture detection logic to IMS, we ideally
// should not rely on PWM to tell us about the gesture start and end.
AidlKeyGestureEvent event = createKeyGestureEvent(deviceId, keycodes, modifierState,
- gestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE, Display.DEFAULT_DISPLAY, 0);
+ gestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE, Display.DEFAULT_DISPLAY,
+ /* flags = */0, /* appLaunchData = */null);
mHandler.obtainMessage(MSG_NOTIFY_KEY_GESTURE_EVENT, event).sendToTarget();
}
public void handleKeyGesture(int deviceId, int[] keycodes, int modifierState,
@KeyGestureEvent.KeyGestureType int gestureType) {
AidlKeyGestureEvent event = createKeyGestureEvent(deviceId, keycodes, modifierState,
- gestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE, Display.DEFAULT_DISPLAY, 0);
+ gestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE, Display.DEFAULT_DISPLAY,
+ /* flags = */0, /* appLaunchData = */null);
handleKeyGesture(event, null /*focusedToken*/);
}
@MainThread
+ public void setCurrentUserId(@UserIdInt int userId) {
+ synchronized (mUserLock) {
+ mCurrentUserId = userId;
+ }
+ }
+
+ @MainThread
private void notifyKeyGestureEvent(AidlKeyGestureEvent event) {
InputDevice device = getInputDevice(event.deviceId);
if (device == null) {
@@ -1367,7 +1398,7 @@ final class KeyGestureController {
private AidlKeyGestureEvent createKeyGestureEvent(int deviceId, int[] keycodes,
int modifierState, @KeyGestureEvent.KeyGestureType int gestureType, int action,
- int displayId, int flags) {
+ int displayId, int flags, @Nullable AppLaunchData appLaunchData) {
AidlKeyGestureEvent event = new AidlKeyGestureEvent();
event.deviceId = deviceId;
event.keycodes = keycodes;
@@ -1376,6 +1407,18 @@ final class KeyGestureController {
event.action = action;
event.displayId = displayId;
event.flags = flags;
+ if (appLaunchData != null) {
+ if (appLaunchData instanceof AppLaunchData.CategoryData categoryData) {
+ event.appLaunchCategory = categoryData.getCategory();
+ } else if (appLaunchData instanceof AppLaunchData.RoleData roleData) {
+ event.appLaunchRole = roleData.getRole();
+ } else if (appLaunchData instanceof AppLaunchData.ComponentData componentData) {
+ event.appLaunchPackageName = componentData.getPackageName();
+ event.appLaunchClassName = componentData.getClassName();
+ } else {
+ throw new IllegalArgumentException("AppLaunchData type is invalid!");
+ }
+ }
return event;
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 849f236916a6..2c45fc89ff0b 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -9363,10 +9363,15 @@ public class NotificationManagerService extends SystemService {
// a group summary or children (complete a group)
mHandler.postDelayed(() -> {
synchronized (mNotificationLock) {
- mGroupHelper.onNotificationPostedWithDelay(
- r, mNotificationList, mSummaryByGroupKey);
+ NotificationRecord record =
+ mNotificationsByKey.get(key);
+ if (record != null) {
+ mGroupHelper.onNotificationPostedWithDelay(
+ record, mNotificationList,
+ mSummaryByGroupKey);
+ }
}
- }, r.getKey(), DELAY_FORCE_REGROUP_TIME);
+ }, key, DELAY_FORCE_REGROUP_TIME);
}
}
@@ -9412,10 +9417,15 @@ public class NotificationManagerService extends SystemService {
if (notificationForceGrouping()) {
mHandler.postDelayed(() -> {
synchronized (mNotificationLock) {
- mGroupHelper.onNotificationPostedWithDelay(r,
- mNotificationList, mSummaryByGroupKey);
+ NotificationRecord record =
+ mNotificationsByKey.get(key);
+ if (record != null) {
+ mGroupHelper.onNotificationPostedWithDelay(
+ record, mNotificationList,
+ mSummaryByGroupKey);
+ }
}
- }, r.getKey(), DELAY_FORCE_REGROUP_TIME);
+ }, key, DELAY_FORCE_REGROUP_TIME);
}
}
}
@@ -10395,7 +10405,7 @@ public class NotificationManagerService extends SystemService {
}
mListeners.notifyRemovedLocked(r, reason, r.getStats());
if (notificationForceGrouping()) {
- mHandler.removeCallbacksAndMessages(r.getKey());
+ mHandler.removeCallbacksAndEqualMessages(r.getKey());
mHandler.post(() -> {
synchronized (NotificationManagerService.this.mNotificationLock) {
mGroupHelper.onNotificationRemoved(r, mNotificationList);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 6c03214a2610..7ecfe7f64ffe 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1222,7 +1222,7 @@ public class UserManagerService extends IUserManager.Stub {
// Mark the user for removal.
addRemovingUserIdLocked(ui.id);
ui.partial = true;
- ui.flags |= UserInfo.FLAG_DISABLED;
+ addUserInfoFlags(ui, UserInfo.FLAG_DISABLED);
}
/* Prunes out any partially created or partially removed users. */
@@ -1264,7 +1264,7 @@ public class UserManagerService extends IUserManager.Stub {
if (ui.preCreated) {
preCreatedUsers.add(ui);
addRemovingUserIdLocked(ui.id);
- ui.flags |= UserInfo.FLAG_DISABLED;
+ addUserInfoFlags(ui, UserInfo.FLAG_DISABLED);
ui.partial = true;
}
}
@@ -2120,7 +2120,7 @@ public class UserManagerService extends IUserManager.Stub {
info = getUserInfoLU(userId);
if (info != null && !info.isEnabled()) {
wasUserDisabled = true;
- info.flags ^= UserInfo.FLAG_DISABLED;
+ removeUserInfoFlags(info, UserInfo.FLAG_DISABLED);
writeUserLP(getUserDataLU(info.id));
}
}
@@ -2130,6 +2130,36 @@ public class UserManagerService extends IUserManager.Stub {
}
}
+ /**
+ * This method is for monitoring flag changes on users flags and invalidate cache relevant to
+ * the change. The method add flags and invalidateOnUserInfoFlagChange for the flags which
+ * has changed.
+ * @param userInfo of existing user in mUsers list
+ * @param flags to be added to userInfo
+ */
+ private void addUserInfoFlags(UserInfo userInfo, @UserInfoFlag int flags) {
+ int diff = ~userInfo.flags & flags;
+ if (diff > 0) {
+ userInfo.flags |= diff;
+ UserManager.invalidateOnUserInfoFlagChange(diff);
+ }
+ }
+
+ /**
+ * This method is for monitoring flag changes on users flags and invalidate cache relevant to
+ * the change. The method remove flags and invalidateOnUserInfoFlagChange for the flags which
+ * has changed.
+ * @param userInfo of existing user in mUsers list
+ * @param flags to be removed from userInfo
+ */
+ private void removeUserInfoFlags(UserInfo userInfo, @UserInfoFlag int flags) {
+ int diff = userInfo.flags & flags;
+ if (diff > 0) {
+ userInfo.flags ^= diff;
+ UserManager.invalidateOnUserInfoFlagChange(diff);
+ }
+ }
+
@Override
public void setUserAdmin(@UserIdInt int userId) {
checkManageUserAndAcrossUsersFullPermission("set user admin");
@@ -6245,7 +6275,7 @@ public class UserManagerService extends IUserManager.Stub {
userData.info.guestToRemove = true;
// Mark it as disabled, so that it isn't returned any more when
// profiles are queried.
- userData.info.flags |= UserInfo.FLAG_DISABLED;
+ addUserInfoFlags(userData.info, UserInfo.FLAG_DISABLED);
writeUserLP(userData);
}
} finally {
@@ -6390,7 +6420,7 @@ public class UserManagerService extends IUserManager.Stub {
}
// Mark it as disabled, so that it isn't returned any more when
// profiles are queried.
- userData.info.flags |= UserInfo.FLAG_DISABLED;
+ addUserInfoFlags(userData.info, UserInfo.FLAG_DISABLED);
writeUserLP(userData);
}
@@ -7789,7 +7819,7 @@ public class UserManagerService extends IUserManager.Stub {
if (userInfo != null && userInfo.isEphemeral()) {
// Do not allow switching back to the ephemeral user again as the user is going
// to be deleted.
- userInfo.flags |= UserInfo.FLAG_DISABLED;
+ addUserInfoFlags(userInfo, UserInfo.FLAG_DISABLED);
if (userInfo.isGuest()) {
// Indicate that the guest will be deleted after it stops.
userInfo.guestToRemove = true;
diff --git a/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java b/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
index c33ed555a7f9..1260eeec098f 100644
--- a/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
+++ b/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
@@ -33,6 +33,7 @@ import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.provider.Settings;
+import android.security.advancedprotection.AdvancedProtectionFeature;
import android.security.advancedprotection.IAdvancedProtectionCallback;
import android.security.advancedprotection.IAdvancedProtectionService;
import android.util.ArrayMap;
@@ -44,9 +45,11 @@ import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.pm.UserManagerInternal;
import com.android.server.security.advancedprotection.features.AdvancedProtectionHook;
+import com.android.server.security.advancedprotection.features.AdvancedProtectionProvider;
import java.io.FileDescriptor;
import java.util.ArrayList;
+import java.util.List;
/** @hide */
public class AdvancedProtectionService extends IAdvancedProtectionService.Stub {
@@ -58,10 +61,12 @@ public class AdvancedProtectionService extends IAdvancedProtectionService.Stub
private final Handler mHandler;
private final AdvancedProtectionStore mStore;
- // Features owned by the service - their code will be executed when state changes
+ // Features living with the service - their code will be executed when state changes
private final ArrayList<AdvancedProtectionHook> mHooks = new ArrayList<>();
// External features - they will be called on state change
private final ArrayMap<IBinder, IAdvancedProtectionCallback> mCallbacks = new ArrayMap<>();
+ // For tracking only - not called on state change
+ private final ArrayList<AdvancedProtectionProvider> mProviders = new ArrayList<>();
private AdvancedProtectionService(@NonNull Context context) {
super(PermissionEnforcer.fromContext(context));
@@ -71,13 +76,17 @@ public class AdvancedProtectionService extends IAdvancedProtectionService.Stub
}
private void initFeatures(boolean enabled) {
+ // Empty until features are added.
+ // Examples:
+ // mHooks.add(new SideloadingAdvancedProtectionHook(mContext, enabled));
+ // mProviders.add(new WifiAdvancedProtectionProvider());
}
// Only for tests
@VisibleForTesting
AdvancedProtectionService(@NonNull Context context, @NonNull AdvancedProtectionStore store,
@NonNull Looper looper, @NonNull PermissionEnforcer permissionEnforcer,
- @Nullable AdvancedProtectionHook hook) {
+ @Nullable AdvancedProtectionHook hook, @Nullable AdvancedProtectionProvider provider) {
super(permissionEnforcer);
mContext = context;
mStore = store;
@@ -85,6 +94,10 @@ public class AdvancedProtectionService extends IAdvancedProtectionService.Stub
if (hook != null) {
mHooks.add(hook);
}
+
+ if (provider != null) {
+ mProviders.add(provider);
+ }
}
@Override
@@ -146,6 +159,25 @@ public class AdvancedProtectionService extends IAdvancedProtectionService.Stub
}
@Override
+ @EnforcePermission(Manifest.permission.SET_ADVANCED_PROTECTION_MODE)
+ public List<AdvancedProtectionFeature> getAdvancedProtectionFeatures() {
+ getAdvancedProtectionFeatures_enforcePermission();
+ List<AdvancedProtectionFeature> features = new ArrayList<>();
+ for (int i = 0; i < mProviders.size(); i++) {
+ features.addAll(mProviders.get(i).getFeatures());
+ }
+
+ for (int i = 0; i < mHooks.size(); i++) {
+ AdvancedProtectionHook hook = mHooks.get(i);
+ if (hook.isAvailable()) {
+ features.add(hook.getFeature());
+ }
+ }
+
+ return features;
+ }
+
+ @Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, @NonNull String[] args, ShellCallback callback,
@NonNull ResultReceiver resultReceiver) {
diff --git a/services/core/java/com/android/server/security/advancedprotection/features/AdvancedProtectionHook.java b/services/core/java/com/android/server/security/advancedprotection/features/AdvancedProtectionHook.java
index b2acc511950b..f82db9676c2c 100644
--- a/services/core/java/com/android/server/security/advancedprotection/features/AdvancedProtectionHook.java
+++ b/services/core/java/com/android/server/security/advancedprotection/features/AdvancedProtectionHook.java
@@ -18,11 +18,15 @@ package com.android.server.security.advancedprotection.features;
import android.annotation.NonNull;
import android.content.Context;
+import android.security.advancedprotection.AdvancedProtectionFeature;
/** @hide */
public abstract class AdvancedProtectionHook {
/** Called on boot phase PHASE_SYSTEM_SERVICES_READY */
public AdvancedProtectionHook(@NonNull Context context, boolean enabled) {}
+ /** The feature this hook provides */
+ @NonNull
+ public abstract AdvancedProtectionFeature getFeature();
/** Whether this feature is relevant on this device. If false, onAdvancedProtectionChanged will
* not be called, and the feature will not be displayed in the onboarding UX. */
public abstract boolean isAvailable();
diff --git a/services/core/java/com/android/server/security/advancedprotection/features/AdvancedProtectionProvider.java b/services/core/java/com/android/server/security/advancedprotection/features/AdvancedProtectionProvider.java
new file mode 100644
index 000000000000..ed451f1e2257
--- /dev/null
+++ b/services/core/java/com/android/server/security/advancedprotection/features/AdvancedProtectionProvider.java
@@ -0,0 +1,27 @@
+/*
+ * 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.security.advancedprotection.features;
+
+import android.security.advancedprotection.AdvancedProtectionFeature;
+
+import java.util.List;
+
+/** @hide */
+public abstract class AdvancedProtectionProvider {
+ /** The list of features provided */
+ public abstract List<AdvancedProtectionFeature> getFeatures();
+}
diff --git a/services/core/java/com/android/server/vibrator/ComposePwleV2VibratorStep.java b/services/core/java/com/android/server/vibrator/ComposePwleV2VibratorStep.java
index d0d6071e9dcb..32a322725692 100644
--- a/services/core/java/com/android/server/vibrator/ComposePwleV2VibratorStep.java
+++ b/services/core/java/com/android/server/vibrator/ComposePwleV2VibratorStep.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.os.Trace;
import android.os.VibrationEffect;
import android.os.vibrator.Flags;
+import android.os.vibrator.PwlePoint;
import android.os.vibrator.PwleSegment;
import android.os.vibrator.VibrationEffectSegment;
import android.util.Slog;
@@ -57,7 +58,7 @@ final class ComposePwleV2VibratorStep extends AbstractComposedVibratorStep {
// Load the next PwleSegments to create a single composePwleV2 call to the vibrator,
// limited to the vibrator's maximum envelope effect size.
int limit = controller.getVibratorInfo().getMaxEnvelopeEffectSize();
- List<PwleSegment> pwles = unrollPwleSegments(effect, segmentIndex, limit);
+ List<PwlePoint> pwles = unrollPwleSegments(effect, segmentIndex, limit);
if (pwles.isEmpty()) {
Slog.w(VibrationThread.TAG, "Ignoring wrong segment for a ComposeEnvelopeStep: "
@@ -70,7 +71,7 @@ final class ComposePwleV2VibratorStep extends AbstractComposedVibratorStep {
Slog.d(VibrationThread.TAG, "Compose " + pwles + " PWLEs on vibrator "
+ controller.getVibratorInfo().getId());
}
- PwleSegment[] pwlesArray = pwles.toArray(new PwleSegment[pwles.size()]);
+ PwlePoint[] pwlesArray = pwles.toArray(new PwlePoint[pwles.size()]);
long vibratorOnResult = controller.on(pwlesArray, getVibration().id);
handleVibratorOnResult(vibratorOnResult);
getVibration().stats.reportComposePwle(vibratorOnResult, pwlesArray);
@@ -82,9 +83,9 @@ final class ComposePwleV2VibratorStep extends AbstractComposedVibratorStep {
}
}
- private List<PwleSegment> unrollPwleSegments(VibrationEffect.Composed effect, int startIndex,
+ private List<PwlePoint> unrollPwleSegments(VibrationEffect.Composed effect, int startIndex,
int limit) {
- List<PwleSegment> segments = new ArrayList<>(limit);
+ List<PwlePoint> pwlePoints = new ArrayList<>(limit);
float bestBreakAmplitude = 1;
int bestBreakPosition = limit; // Exclusive index.
@@ -93,7 +94,7 @@ final class ComposePwleV2VibratorStep extends AbstractComposedVibratorStep {
// Loop once after reaching the limit to see if breaking it will really be necessary, then
// apply the best break position found, otherwise return the full list as it fits the limit.
- for (int i = startIndex; segments.size() <= limit; i++) {
+ for (int i = startIndex; pwlePoints.size() < limit; i++) {
if (i == segmentCount) {
if (repeatIndex >= 0) {
i = repeatIndex;
@@ -104,12 +105,20 @@ final class ComposePwleV2VibratorStep extends AbstractComposedVibratorStep {
}
VibrationEffectSegment segment = effect.getSegments().get(i);
if (segment instanceof PwleSegment pwleSegment) {
- segments.add(pwleSegment);
+ if (pwlePoints.isEmpty()) {
+ // The initial state is defined by the starting amplitude and frequency of the
+ // first PwleSegment. The time parameter is set to zero to indicate this is
+ // the initial condition without any ramp up time.
+ pwlePoints.add(new PwlePoint(pwleSegment.getStartAmplitude(),
+ pwleSegment.getStartFrequencyHz(), /*timeMillis=*/ 0));
+ }
+ pwlePoints.add(new PwlePoint(pwleSegment.getEndAmplitude(),
+ pwleSegment.getEndFrequencyHz(), (int) pwleSegment.getDuration()));
- if (isBetterBreakPosition(segments, bestBreakAmplitude, limit)) {
+ if (isBetterBreakPosition(pwlePoints, bestBreakAmplitude, limit)) {
// Mark this position as the best one so far to break a long waveform.
bestBreakAmplitude = pwleSegment.getEndAmplitude();
- bestBreakPosition = segments.size(); // Break after this pwle ends.
+ bestBreakPosition = pwlePoints.size(); // Break after this pwle ends.
}
} else {
// First non-pwle segment, stop collecting pwles.
@@ -117,21 +126,21 @@ final class ComposePwleV2VibratorStep extends AbstractComposedVibratorStep {
}
}
- return segments.size() > limit
+ return pwlePoints.size() > limit
// Remove excessive segments, using the best breaking position recorded.
- ? segments.subList(0, bestBreakPosition)
+ ? pwlePoints.subList(0, bestBreakPosition)
// Return all collected pwle segments.
- : segments;
+ : pwlePoints;
}
/**
* Returns true if the current segment list represents a better break position for a PWLE,
* given the current amplitude being used for breaking it at a smaller size and the size limit.
*/
- private boolean isBetterBreakPosition(List<PwleSegment> segments,
+ private boolean isBetterBreakPosition(List<PwlePoint> segments,
float currentBestBreakAmplitude, int limit) {
- PwleSegment lastSegment = segments.get(segments.size() - 1);
- float breakAmplitudeCandidate = lastSegment.getEndAmplitude();
+ PwlePoint lastSegment = segments.get(segments.size() - 1);
+ float breakAmplitudeCandidate = lastSegment.getAmplitude();
int breakPositionCandidate = segments.size();
if (breakPositionCandidate > limit) {
diff --git a/services/core/java/com/android/server/vibrator/VibrationStats.java b/services/core/java/com/android/server/vibrator/VibrationStats.java
index bc4dbe75b37e..de423f061b2b 100644
--- a/services/core/java/com/android/server/vibrator/VibrationStats.java
+++ b/services/core/java/com/android/server/vibrator/VibrationStats.java
@@ -22,7 +22,7 @@ import android.os.CombinedVibration;
import android.os.SystemClock;
import android.os.vibrator.PrebakedSegment;
import android.os.vibrator.PrimitiveSegment;
-import android.os.vibrator.PwleSegment;
+import android.os.vibrator.PwlePoint;
import android.os.vibrator.RampSegment;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -294,18 +294,22 @@ final class VibrationStats {
}
/** Report a call to vibrator method to trigger a vibration as a PWLE. */
- void reportComposePwle(long halResult, PwleSegment[] segments) {
+ void reportComposePwle(long halResult, PwlePoint[] pwlePoints) {
mVibratorComposePwleCount++;
- mVibrationPwleTotalSize += segments.length;
+ mVibrationPwleTotalSize += pwlePoints.length;
if (halResult > 0) {
// If HAL result is positive then it represents the actual duration of the vibration.
// Remove the zero-amplitude segments to update the total time the vibrator was ON.
- for (PwleSegment ramp : segments) {
- if ((ramp.getStartAmplitude() == 0) && (ramp.getEndAmplitude() == 0)) {
- halResult -= ramp.getDuration();
+ for (int i = 0; i < pwlePoints.length - 1; i++) {
+ PwlePoint current = pwlePoints[i];
+ PwlePoint next = pwlePoints[i + 1];
+
+ if (current.getAmplitude() == 0 && next.getAmplitude() == 0) {
+ halResult -= next.getTimeMillis();
}
}
+
if (halResult > 0) {
mVibratorOnTotalDurationMillis += (int) halResult;
}
diff --git a/services/core/java/com/android/server/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java
index f78bff8e229d..acb31ceb4027 100644
--- a/services/core/java/com/android/server/vibrator/VibratorController.java
+++ b/services/core/java/com/android/server/vibrator/VibratorController.java
@@ -30,7 +30,7 @@ import android.os.VibrationEffect;
import android.os.VibratorInfo;
import android.os.vibrator.PrebakedSegment;
import android.os.vibrator.PrimitiveSegment;
-import android.os.vibrator.PwleSegment;
+import android.os.vibrator.PwlePoint;
import android.os.vibrator.RampSegment;
import android.util.IndentingPrintWriter;
import android.util.Slog;
@@ -415,21 +415,21 @@ final class VibratorController {
}
/**
- * Plays a composition of pwle v2 primitives, using {@code vibrationId} for completion callback
+ * Plays a composition of pwle v2 points, using {@code vibrationId} for completion callback
* to {@link OnVibrationCompleteListener}.
*
* <p>This will affect the state of {@link #isVibrating()}.
*
* @return The duration of the effect playing, or 0 if unsupported.
*/
- public long on(PwleSegment[] primitives, long vibrationId) {
+ public long on(PwlePoint[] pwlePoints, long vibrationId) {
Trace.traceBegin(TRACE_TAG_VIBRATOR, "VibratorController#on (PWLE v2)");
try {
if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2)) {
return 0;
}
synchronized (mLock) {
- long duration = mNativeWrapper.composePwleV2(primitives, vibrationId);
+ long duration = mNativeWrapper.composePwleV2(pwlePoints, vibrationId);
if (duration > 0) {
mCurrentAmplitude = -1;
updateStateAndNotifyListenersLocked(VibratorState.VIBRATING);
@@ -562,7 +562,7 @@ final class VibratorController {
private static native long performPwleEffect(long nativePtr, RampSegment[] effect,
int braking, long vibrationId);
- private static native long performPwleV2Effect(long nativePtr, PwleSegment[] effect,
+ private static native long performPwleV2Effect(long nativePtr, PwlePoint[] effect,
long vibrationId);
private static native void setExternalControl(long nativePtr, boolean enabled);
@@ -631,9 +631,9 @@ final class VibratorController {
return performPwleEffect(mNativePtr, primitives, braking, vibrationId);
}
- /** Turns vibrator on to perform PWLE effect composed of given primitives. */
- public long composePwleV2(PwleSegment[] primitives, long vibrationId) {
- return performPwleV2Effect(mNativePtr, primitives, vibrationId);
+ /** Turns vibrator on to perform PWLE effect composed of given points. */
+ public long composePwleV2(PwlePoint[] pwlePoints, long vibrationId) {
+ return performPwleV2Effect(mNativePtr, pwlePoints, vibrationId);
}
/** Enabled the device vibrator to be controlled by another service. */
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java b/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
index cf76bf05ab19..d754bdf93b96 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
@@ -745,9 +745,9 @@ public class WallpaperDataParser {
private static List<Pair<Integer, String>> screenDimensionPairs() {
return List.of(
- new Pair<>(WallpaperManager.PORTRAIT, "Portrait"),
- new Pair<>(WallpaperManager.LANDSCAPE, "Landscape"),
- new Pair<>(WallpaperManager.SQUARE_PORTRAIT, "SquarePortrait"),
- new Pair<>(WallpaperManager.SQUARE_LANDSCAPE, "SquareLandscape"));
+ new Pair<>(WallpaperManager.ORIENTATION_PORTRAIT, "Portrait"),
+ new Pair<>(WallpaperManager.ORIENTATION_LANDSCAPE, "Landscape"),
+ new Pair<>(WallpaperManager.ORIENTATION_SQUARE_PORTRAIT, "SquarePortrait"),
+ new Pair<>(WallpaperManager.ORIENTATION_SQUARE_LANDSCAPE, "SquareLandscape"));
}
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 744c3da6d6dc..e1fa8848b0e1 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -78,8 +78,13 @@ public class WebViewUpdateService extends SystemService {
mWebViewUpdatedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (action == null) {
+ return;
+ }
+
int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
- switch (intent.getAction()) {
+ switch (action) {
case Intent.ACTION_PACKAGE_REMOVED:
// When a package is replaced we will receive two intents, one
// representing the removal of the old package and one representing the
diff --git a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
index fa5beca31ec1..ea6506a03a80 100644
--- a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
+++ b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
@@ -40,7 +40,6 @@ class ActivityRecordInputSink {
@ChangeId
static final long ENABLE_TOUCH_OPAQUE_ACTIVITIES = 194480991L;
- // TODO(b/369605358) Update EnabledSince when SDK 36 version code is available.
/**
* If the app's target SDK is 36+, pass-through touches from a cross-uid overlaying activity is
* blocked by default. The activity may opt in to receive pass-through touches using
@@ -52,7 +51,7 @@ class ActivityRecordInputSink {
* @see ActivityOptions#setAllowPassThroughOnTouchOutside
*/
@ChangeId
- @EnabledSince(targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT)
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.BAKLAVA)
static final long ENABLE_OVERLAY_TOUCH_PASS_THROUGH_OPT_IN_ENFORCEMENT = 358129114L;
private final ActivityRecord mActivityRecord;
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 6e97f8a943dd..3f24da9d89f2 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -478,7 +478,7 @@ public class ActivityStartController {
intentGrants.merge(creatorIntentGrants);
}
} catch (SecurityException securityException) {
- ActivityStarter.logAndThrowExceptionForIntentRedirect(
+ ActivityStarter.logAndThrowExceptionForIntentRedirect(mService.mContext,
"Creator URI Grant Caused Exception.", intent, creatorUid,
creatorPackage, filterCallingUid, callingPackage,
securityException);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index e15968db9b3d..05a96d9fcf5e 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -55,6 +55,7 @@ import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
import static android.content.pm.ActivityInfo.launchModeToString;
import static android.os.Process.INVALID_UID;
import static android.security.Flags.preventIntentRedirectAbortOrThrowException;
+import static android.security.Flags.preventIntentRedirectShowToast;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_OPEN;
@@ -105,6 +106,7 @@ import android.compat.annotation.ChangeId;
import android.compat.annotation.Disabled;
import android.compat.annotation.EnabledSince;
import android.compat.annotation.Overridable;
+import android.content.Context;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
@@ -128,12 +130,14 @@ import android.service.voice.IVoiceInteractionSession;
import android.text.TextUtils;
import android.util.Pools.SynchronizedPool;
import android.util.Slog;
+import android.widget.Toast;
import android.window.RemoteTransition;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.protolog.ProtoLog;
+import com.android.server.UiThread;
import com.android.server.am.ActivityManagerService.IntentCreatorToken;
import com.android.server.am.PendingIntentRecord;
import com.android.server.pm.InstantAppResolver;
@@ -614,7 +618,7 @@ class ActivityStarter {
// Check if the Intent was redirected
if ((intent.getExtendedFlags() & Intent.EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN)
!= 0) {
- ActivityStarter.logAndThrowExceptionForIntentRedirect(
+ logAndThrowExceptionForIntentRedirect(supervisor.mService.mContext,
"Unparceled intent does not have a creator token set.", intent,
intentCreatorUid, intentCreatorPackage, resolvedCallingUid,
resolvedCallingPackage, null);
@@ -650,7 +654,7 @@ class ActivityStarter {
intentGrants.merge(creatorIntentGrants);
}
} catch (SecurityException securityException) {
- ActivityStarter.logAndThrowExceptionForIntentRedirect(
+ logAndThrowExceptionForIntentRedirect(supervisor.mService.mContext,
"Creator URI Grant Caused Exception.", intent, intentCreatorUid,
intentCreatorPackage, resolvedCallingUid,
resolvedCallingPackage, securityException);
@@ -674,7 +678,7 @@ class ActivityStarter {
intentGrants.merge(creatorIntentGrants);
}
} catch (SecurityException securityException) {
- ActivityStarter.logAndThrowExceptionForIntentRedirect(
+ logAndThrowExceptionForIntentRedirect(supervisor.mService.mContext,
"Creator URI Grant Caused Exception.", intent, intentCreatorUid,
intentCreatorPackage, resolvedCallingUid,
resolvedCallingPackage, securityException);
@@ -1250,27 +1254,27 @@ class ActivityStarter {
requestCode, 0, intentCreatorUid, intentCreatorPackage, "",
request.ignoreTargetSecurity, inTask != null, null, resultRecord,
resultRootTask)) {
- abort = logAndAbortForIntentRedirect(
+ abort = logAndAbortForIntentRedirect(mService.mContext,
"Creator checkStartAnyActivityPermission Caused abortion.",
intent, intentCreatorUid, intentCreatorPackage, callingUid,
callingPackage);
}
} catch (SecurityException e) {
- logAndThrowExceptionForIntentRedirect(
+ logAndThrowExceptionForIntentRedirect(mService.mContext,
"Creator checkStartAnyActivityPermission Caused Exception.",
intent, intentCreatorUid, intentCreatorPackage, callingUid, callingPackage,
e);
}
if (!mService.mIntentFirewall.checkStartActivity(intent, intentCreatorUid,
0, resolvedType, aInfo.applicationInfo)) {
- abort = logAndAbortForIntentRedirect(
+ abort = logAndAbortForIntentRedirect(mService.mContext,
"Creator IntentFirewall.checkStartActivity Caused abortion.",
intent, intentCreatorUid, intentCreatorPackage, callingUid, callingPackage);
}
if (!mService.getPermissionPolicyInternal().checkStartActivity(intent,
intentCreatorUid, intentCreatorPackage)) {
- abort = logAndAbortForIntentRedirect(
+ abort = logAndAbortForIntentRedirect(mService.mContext,
"Creator PermissionPolicyService.checkStartActivity Caused abortion.",
intent, intentCreatorUid, intentCreatorPackage, callingUid, callingPackage);
}
@@ -3596,25 +3600,38 @@ class ActivityStarter {
pw.println(mInTaskFragment);
}
- static void logAndThrowExceptionForIntentRedirect(@NonNull String message,
- @NonNull Intent intent, int intentCreatorUid, @Nullable String intentCreatorPackage,
- int callingUid, @Nullable String callingPackage,
+ static void logAndThrowExceptionForIntentRedirect(@NonNull Context context,
+ @NonNull String message, @NonNull Intent intent, int intentCreatorUid,
+ @Nullable String intentCreatorPackage, int callingUid, @Nullable String callingPackage,
@Nullable SecurityException originalException) {
String msg = getIntentRedirectPreventedLogMessage(message, intent, intentCreatorUid,
intentCreatorPackage, callingUid, callingPackage);
Slog.wtf(TAG, msg);
+ if (preventIntentRedirectShowToast()) {
+ UiThread.getHandler().post(
+ () -> Toast.makeText(context,
+ "Activity launch blocked. go/report-bug-intentRedir to report a bug",
+ Toast.LENGTH_LONG).show());
+ }
if (preventIntentRedirectAbortOrThrowException() && CompatChanges.isChangeEnabled(
ENABLE_PREVENT_INTENT_REDIRECT_TAKE_ACTION, callingUid)) {
throw new SecurityException(msg, originalException);
}
}
- private static boolean logAndAbortForIntentRedirect(@NonNull String message,
- @NonNull Intent intent, int intentCreatorUid, @Nullable String intentCreatorPackage,
- int callingUid, @Nullable String callingPackage) {
+ private static boolean logAndAbortForIntentRedirect(@NonNull Context context,
+ @NonNull String message, @NonNull Intent intent, int intentCreatorUid,
+ @Nullable String intentCreatorPackage, int callingUid,
+ @Nullable String callingPackage) {
String msg = getIntentRedirectPreventedLogMessage(message, intent, intentCreatorUid,
intentCreatorPackage, callingUid, callingPackage);
Slog.wtf(TAG, msg);
+ if (preventIntentRedirectShowToast()) {
+ UiThread.getHandler().post(
+ () -> Toast.makeText(context,
+ "Activity launch blocked. go/report-bug-intentRedir to report a bug",
+ Toast.LENGTH_LONG).show());
+ }
return preventIntentRedirectAbortOrThrowException() && CompatChanges.isChangeEnabled(
ENABLE_PREVENT_INTENT_REDIRECT_TAKE_ACTION, callingUid);
}
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 1933408afae5..5424741d5e00 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -1164,8 +1164,9 @@ public class BackgroundActivityStartController {
* or {@link #BAL_BLOCK} if the launch should be blocked
*/
BalVerdict checkBackgroundActivityStartAllowedByRealCallerInBackground(BalState state) {
- if (state.mCheckedOptions.getPendingIntentBackgroundActivityStartMode()
- == MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS
+ boolean allowAlways = state.mCheckedOptions.getPendingIntentBackgroundActivityStartMode()
+ == MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS;
+ if (allowAlways
&& hasBalPermission(state.mRealCallingUid, state.mRealCallingPid)) {
return new BalVerdict(BAL_ALLOW_PERMISSION,
/*background*/ false,
@@ -1177,8 +1178,7 @@ public class BackgroundActivityStartController {
+ state.mRealCallingPid + ", " + state.mRealCallingPackage + ") "
+ balStartModeToString(
state.mCheckedOptions.getPendingIntentBackgroundActivityStartMode()));
- if (state.mCheckedOptions.getPendingIntentBackgroundActivityStartMode()
- == MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS
+ if (allowAlways
&& mService.hasSystemAlertWindowPermission(state.mRealCallingUid,
state.mRealCallingPid, state.mRealCallingPackage)) {
Slog.w(
@@ -1192,7 +1192,7 @@ public class BackgroundActivityStartController {
// if the realCallingUid is a persistent system process, abort if the IntentSender
// wasn't allowed to start an activity
- if (state.mAllowBalExemptionForSystemProcess
+ if ((allowAlways || state.mAllowBalExemptionForSystemProcess)
&& state.mIsRealCallingUidPersistentSystemProcess) {
return new BalVerdict(BAL_ALLOW_ALLOWLISTED_UID,
/*background*/ false,
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 8aa0530d3bc1..8986750d3c2e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3917,8 +3917,10 @@ class Task extends TaskFragment {
sb.append(affinityIntent.getComponent().flattenToShortString());
}
sb.append(" isResizeable=").append(isResizeable());
- sb.append(" minWidth=").append(mMinWidth);
- sb.append(" minHeight=").append(mMinHeight);
+ if (mMinWidth != INVALID_MIN_SIZE || mMinHeight != INVALID_MIN_SIZE) {
+ sb.append(" minWidth=").append(mMinWidth);
+ sb.append(" minHeight=").append(mMinHeight);
+ }
sb.append('}');
return stringName = sb.toString();
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index fc4660061c55..454e43120ede 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -237,15 +237,16 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
private final ArraySet<WindowToken> mVisibleAtTransitionEndTokens = new ArraySet<>();
/**
- * Set of transient activities (lifecycle initially tied to this transition) and their
+ * Map of transient activities (lifecycle initially tied to this transition) to their
* restore-below tasks.
*/
private ArrayMap<ActivityRecord, Task> mTransientLaunches = null;
/**
* The tasks that may be occluded by the transient activity. Assume the task stack is
- * [Home, A(opaque), B(opaque), C(translucent)] (bottom to top), then A is the restore-below
- * task, and [B, C] are the transient-hide tasks.
+ * [Home, A(opaque), B(opaque), C(translucent)] (bottom to top), and Home is started in a
+ * transient-launch activity, then A is the restore-below task, and [B, C] are the
+ * transient-hide tasks.
*/
private ArrayList<Task> mTransientHideTasks;
@@ -401,18 +402,26 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
mTransientLaunches.put(activity, restoreBelow);
setTransientLaunchToChanges(activity);
- final Task transientRootTask = activity.getRootTask();
+ final int restoreBelowTaskId = restoreBelow != null ? restoreBelow.mTaskId : -1;
+ ProtoLog.v(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS, "Transition %d: Set %s as "
+ + "transient-launch restoreBelowTaskId=%d", mSyncId, activity, restoreBelowTaskId);
+
+ final Task transientLaunchRootTask = activity.getRootTask();
final WindowContainer<?> parent = restoreBelow != null ? restoreBelow.getParent()
- : (transientRootTask != null ? transientRootTask.getParent() : null);
+ : (transientLaunchRootTask != null ? transientLaunchRootTask.getParent() : null);
if (parent != null) {
// Collect all visible tasks which can be occluded by the transient activity to
// make sure they are in the participants so their visibilities can be updated when
// finishing transition.
+ // Note: This currently assumes that the parent is a DA containing the full set of
+ // visible tasks
parent.forAllTasks(t -> {
// Skip transient-launch task
- if (t == transientRootTask) return false;
+ if (t == transientLaunchRootTask) return false;
if (t.isVisibleRequested() && !t.isAlwaysOnTop()) {
if (t.isRootTask()) {
+ ProtoLog.v(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS,
+ " transient hide: taskId=%d", t.mTaskId);
mTransientHideTasks.add(t);
}
if (t.isLeafTask()) {
@@ -442,9 +451,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
// the gesture threshold.
activity.getTask().setCanAffectSystemUiFlags(false);
}
-
- ProtoLog.v(WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS, "Transition %d: Set %s as "
- + "transient-launch", mSyncId, activity);
}
/** @return whether `wc` is a descendent of a transient-hide window. */
@@ -462,6 +468,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
/** Returns {@code true} if the task should keep visible if this is a transient transition. */
boolean isTransientVisible(@NonNull Task task) {
if (mTransientLaunches == null) return false;
+
+ // Check if all the transient-launch activities are occluded
int occludedCount = 0;
final int numTransient = mTransientLaunches.size();
for (int i = numTransient - 1; i >= 0; --i) {
@@ -486,6 +494,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
// Let transient-hide activities pause before transition is finished.
return false;
}
+
+ // If this task is currently transient-hide, then keep it visible
return isInTransientHide(task);
}
@@ -608,7 +618,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
}
/**
- * Only set flag to the parent tasks and activity itself.
+ * Sets the FLAG_TRANSIENT_LAUNCH flag to all changes associated with the given activity
+ * container and parent tasks.
*/
private void setTransientLaunchToChanges(@NonNull WindowContainer wc) {
for (WindowContainer curr = wc; curr != null && mChanges.containsKey(curr);
@@ -774,7 +785,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
// Only look at tasks, taskfragments, or activities
if (wc.asTaskFragment() == null && wc.asActivityRecord() == null) return;
if (!isInTransientHide(wc)) return;
- info.mFlags |= ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH;
+ info.mFlags |= ChangeInfo.FLAG_TRANSIENT_HIDE;
}
private void recordDisplay(DisplayContent dc) {
@@ -2448,6 +2459,13 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
sb.append(" type=" + transitTypeToString(mType));
sb.append(" flags=0x" + Integer.toHexString(mFlags));
sb.append(" overrideAnimOptions=" + mOverrideOptions);
+ if (!mChanges.isEmpty()) {
+ sb.append(" c=[");
+ for (int i = 0; i < mChanges.size(); i++) {
+ sb.append("\n").append(" ").append(mChanges.valueAt(i).toString());
+ }
+ sb.append("\n]\n");
+ }
sb.append('}');
return sb.toString();
}
@@ -3396,8 +3414,14 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
* seamless rotation. This is currently only used by DisplayContent during fixed-rotation.
*/
private static final int FLAG_SEAMLESS_ROTATION = 1;
+ /**
+ * Identifies the associated WindowContainer as a transient-launch task or activity.
+ */
private static final int FLAG_TRANSIENT_LAUNCH = 2;
- private static final int FLAG_ABOVE_TRANSIENT_LAUNCH = 4;
+ /**
+ * Identifies the associated WindowContainer as a transient-hide task or activity.
+ */
+ private static final int FLAG_TRANSIENT_HIDE = 4;
/** This container explicitly requested no-animation (usually Activity level). */
private static final int FLAG_CHANGE_NO_ANIMATION = 0x8;
@@ -3429,7 +3453,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
FLAG_NONE,
FLAG_SEAMLESS_ROTATION,
FLAG_TRANSIENT_LAUNCH,
- FLAG_ABOVE_TRANSIENT_LAUNCH,
+ FLAG_TRANSIENT_HIDE,
FLAG_CHANGE_NO_ANIMATION,
FLAG_CHANGE_YES_ANIMATION,
FLAG_CHANGE_MOVED_TO_TOP,
@@ -3438,7 +3462,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
FLAG_BELOW_BACK_GESTURE_ANIMATION
})
@Retention(RetentionPolicy.SOURCE)
- @interface Flag {}
+ @interface ChangeInfoFlag {}
@NonNull final WindowContainer mContainer;
/**
@@ -3467,7 +3491,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
@ActivityInfo.Config int mKnownConfigChanges;
/** Extra information about this change. */
- @Flag int mFlags = FLAG_NONE;
+ @ChangeInfoFlag int mFlags = FLAG_NONE;
/** Snapshot surface and luma, if relevant. */
SurfaceControl mSnapshot;
@@ -3502,14 +3526,20 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
@Override
public String toString() {
- return mContainer.toString();
+ StringBuilder sb = new StringBuilder(64);
+ sb.append("ChangeInfo{");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(" container=").append(mContainer);
+ sb.append(" flags=0x").append(Integer.toHexString(mFlags));
+ sb.append('}');
+ return sb.toString();
}
boolean hasChanged() {
final boolean currVisible = mContainer.isVisibleRequested();
// the task including transient launch must promote to root task
if (currVisible && ((mFlags & ChangeInfo.FLAG_TRANSIENT_LAUNCH) != 0
- || (mFlags & ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH) != 0)
+ || (mFlags & ChangeInfo.FLAG_TRANSIENT_HIDE) != 0)
|| (mFlags & ChangeInfo.FLAG_BACK_GESTURE_ANIMATION) != 0
|| (mFlags & ChangeInfo.FLAG_BELOW_BACK_GESTURE_ANIMATION) != 0) {
return true;
@@ -3530,7 +3560,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
@TransitionInfo.TransitionMode
int getTransitMode(@NonNull WindowContainer wc) {
- if ((mFlags & ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH) != 0) {
+ if ((mFlags & ChangeInfo.FLAG_TRANSIENT_HIDE) != 0) {
return mExistenceChanged ? TRANSIT_CLOSE : TRANSIT_TO_BACK;
}
if ((mFlags & ChangeInfo.FLAG_BELOW_BACK_GESTURE_ANIMATION) != 0) {
diff --git a/services/core/java/com/android/server/wm/TransparentPolicy.java b/services/core/java/com/android/server/wm/TransparentPolicy.java
index 85a118db36eb..edd99243c3ef 100644
--- a/services/core/java/com/android/server/wm/TransparentPolicy.java
+++ b/services/core/java/com/android/server/wm/TransparentPolicy.java
@@ -196,10 +196,11 @@ class TransparentPolicy {
// We evaluate the case when the policy should not be applied.
private boolean shouldSkipTransparentPolicy(@Nullable ActivityRecord opaqueActivity) {
- if (opaqueActivity == null || opaqueActivity.isEmbedded()) {
+ if (opaqueActivity == null || opaqueActivity.isEmbedded()
+ || !opaqueActivity.areBoundsLetterboxed()) {
// We skip letterboxing if the translucent activity doesn't have any
// opaque activities beneath or the activity below is embedded which
- // never has letterbox.
+ // never has letterbox or the activity is not letterboxed at all.
return true;
}
final AppCompatSizeCompatModePolicy scmPolicy = mActivityRecord.mAppCompatController
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 6c92ae6bb3e7..e0c473de0f33 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1117,7 +1117,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
*/
void onDisplayChanged(DisplayContent dc) {
if (mDisplayContent != null && mDisplayContent != dc) {
- mTransitionController.collect(this);
+ if (asWindowState() == null) {
+ mTransitionController.collect(this);
+ }
// Cancel any change transition queued-up for this container on the old display when
// this container is moved from the old display.
mDisplayContent.mClosingChangingContainers.remove(this);
@@ -2119,7 +2121,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
/**
- * For all tasks at or below this container call the callback.
+ * Calls the given {@param callback} for all tasks in depth-first top-down z-order at or below
+ * this container.
*
* @param callback Calls the {@link ToBooleanFunction#apply} method for each task found and
* stops the search if {@link ToBooleanFunction#apply} returns {@code true}.
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 585e61795e7d..d01e29b2fd5e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -258,6 +258,7 @@ import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
import com.android.server.wm.RefreshRatePolicy.FrameRateVote;
import com.android.server.wm.SurfaceAnimator.AnimationType;
+import com.android.server.wm.utils.RegionUtils;
import com.android.window.flags.Flags;
import dalvik.annotation.optimization.NeverCompile;
@@ -2327,7 +2328,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (mStartingData != null && mStartingData.mAssociatedTask == null
&& mTempConfiguration.windowConfiguration.getRotation()
== selfConfiguration.windowConfiguration.getRotation()
- && !mTempConfiguration.windowConfiguration.getBounds().equals(getBounds())) {
+ && !RegionUtils.sizeEquals(
+ mTempConfiguration.windowConfiguration.getBounds(), getBounds())) {
mStartingData.mResizedFromTransfer = true;
// Lock the starting window to task, so it won't resize from transfer anymore.
mActivityRecord.associateStartingWindowWithTaskIfNeeded();
diff --git a/services/core/java/com/android/server/wm/utils/RegionUtils.java b/services/core/java/com/android/server/wm/utils/RegionUtils.java
index ff23145fc6b9..6c5da175644b 100644
--- a/services/core/java/com/android/server/wm/utils/RegionUtils.java
+++ b/services/core/java/com/android/server/wm/utils/RegionUtils.java
@@ -92,4 +92,9 @@ public class RegionUtils {
}
return area;
}
+
+ /** Returns whether the sizes between the two Rects are equal. */
+ public static boolean sizeEquals(Rect a, Rect b) {
+ return a.width() == b.width() && a.height() == b.height();
+ }
}
diff --git a/services/core/jni/com_android_server_vibrator_VibratorController.cpp b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
index 59dbf28b3d1c..0ecc0a8a9524 100644
--- a/services/core/jni/com_android_server_vibrator_VibratorController.cpp
+++ b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
@@ -74,12 +74,10 @@ static struct {
jfieldID duration;
} sRampClassInfo;
static struct {
- jfieldID startAmplitude;
- jfieldID endAmplitude;
- jfieldID startFrequencyHz;
- jfieldID endFrequencyHz;
- jfieldID duration;
-} sPwleClassInfo;
+ jfieldID amplitude;
+ jfieldID frequencyHz;
+ jfieldID timeMillis;
+} sPwlePointClassInfo;
static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) ==
static_cast<uint8_t>(Aidl::EffectStrength::LIGHT));
@@ -191,10 +189,11 @@ static Aidl::ActivePwle activePwleFromJavaPrimitive(JNIEnv* env, jobject ramp) {
static Aidl::PwleV2Primitive pwleV2PrimitiveFromJavaPrimitive(JNIEnv* env, jobject pwleObj) {
Aidl::PwleV2Primitive pwle;
- pwle.amplitude = static_cast<float>(env->GetFloatField(pwleObj, sPwleClassInfo.endAmplitude));
+ pwle.amplitude = static_cast<float>(env->GetFloatField(pwleObj, sPwlePointClassInfo.amplitude));
pwle.frequencyHz =
- static_cast<float>(env->GetFloatField(pwleObj, sPwleClassInfo.endFrequencyHz));
- pwle.timeMillis = static_cast<int32_t>(env->GetIntField(pwleObj, sPwleClassInfo.duration));
+ static_cast<float>(env->GetFloatField(pwleObj, sPwlePointClassInfo.frequencyHz));
+ pwle.timeMillis =
+ static_cast<int32_t>(env->GetIntField(pwleObj, sPwlePointClassInfo.timeMillis));
return pwle;
}
@@ -620,7 +619,7 @@ static const JNINativeMethod method_table[] = {
(void*)vibratorPerformComposedEffect},
{"performPwleEffect", "(J[Landroid/os/vibrator/RampSegment;IJ)J",
(void*)vibratorPerformPwleEffect},
- {"performPwleV2Effect", "(J[Landroid/os/vibrator/PwleSegment;J)J",
+ {"performPwleV2Effect", "(J[Landroid/os/vibrator/PwlePoint;J)J",
(void*)vibratorPerformPwleV2Effect},
{"setExternalControl", "(JZ)V", (void*)vibratorSetExternalControl},
{"alwaysOnEnable", "(JJJJ)V", (void*)vibratorAlwaysOnEnable},
@@ -647,12 +646,10 @@ int register_android_server_vibrator_VibratorController(JavaVM* jvm, JNIEnv* env
sRampClassInfo.endFrequencyHz = GetFieldIDOrDie(env, rampClass, "mEndFrequencyHz", "F");
sRampClassInfo.duration = GetFieldIDOrDie(env, rampClass, "mDuration", "I");
- jclass pwleClass = FindClassOrDie(env, "android/os/vibrator/PwleSegment");
- sPwleClassInfo.startAmplitude = GetFieldIDOrDie(env, pwleClass, "mStartAmplitude", "F");
- sPwleClassInfo.endAmplitude = GetFieldIDOrDie(env, pwleClass, "mEndAmplitude", "F");
- sPwleClassInfo.startFrequencyHz = GetFieldIDOrDie(env, pwleClass, "mStartFrequencyHz", "F");
- sPwleClassInfo.endFrequencyHz = GetFieldIDOrDie(env, pwleClass, "mEndFrequencyHz", "F");
- sPwleClassInfo.duration = GetFieldIDOrDie(env, pwleClass, "mDuration", "I");
+ jclass pwlePointClass = FindClassOrDie(env, "android/os/vibrator/PwlePoint");
+ sPwlePointClassInfo.amplitude = GetFieldIDOrDie(env, pwlePointClass, "mAmplitude", "F");
+ sPwlePointClassInfo.frequencyHz = GetFieldIDOrDie(env, pwlePointClass, "mFrequencyHz", "F");
+ sPwlePointClassInfo.timeMillis = GetFieldIDOrDie(env, pwlePointClass, "mTimeMillis", "I");
jclass frequencyProfileLegacyClass =
FindClassOrDie(env, "android/os/VibratorInfo$FrequencyProfileLegacy");
diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperCropperTest.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperCropperTest.java
index f1bf86f2f57c..b53f6fbee183 100644
--- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperCropperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperCropperTest.java
@@ -16,11 +16,11 @@
package com.android.server.wallpaper;
-import static android.app.WallpaperManager.LANDSCAPE;
+import static android.app.WallpaperManager.ORIENTATION_LANDSCAPE;
import static android.app.WallpaperManager.ORIENTATION_UNKNOWN;
-import static android.app.WallpaperManager.PORTRAIT;
-import static android.app.WallpaperManager.SQUARE_LANDSCAPE;
-import static android.app.WallpaperManager.SQUARE_PORTRAIT;
+import static android.app.WallpaperManager.ORIENTATION_PORTRAIT;
+import static android.app.WallpaperManager.ORIENTATION_SQUARE_LANDSCAPE;
+import static android.app.WallpaperManager.ORIENTATION_SQUARE_PORTRAIT;
import static android.app.WallpaperManager.getOrientation;
import static android.app.WallpaperManager.getRotatedOrientation;
@@ -406,15 +406,16 @@ public class WallpaperCropperTest {
setUpWithDisplays(STANDARD_DISPLAY);
Point bitmapSize = new Point(800, 1000);
SparseArray<Rect> suggestedCrops = new SparseArray<>();
- suggestedCrops.put(PORTRAIT, new Rect(0, 0, 400, 800));
- for (int otherOrientation: List.of(LANDSCAPE, SQUARE_LANDSCAPE, SQUARE_PORTRAIT)) {
+ suggestedCrops.put(ORIENTATION_PORTRAIT, new Rect(0, 0, 400, 800));
+ for (int otherOrientation: List.of(ORIENTATION_LANDSCAPE, ORIENTATION_SQUARE_LANDSCAPE,
+ ORIENTATION_SQUARE_PORTRAIT)) {
suggestedCrops.put(otherOrientation, new Rect(0, 0, 10, 10));
}
for (boolean rtl : List.of(false, true)) {
assertThat(mWallpaperCropper.getCrop(
new Point(300, 800), bitmapSize, suggestedCrops, rtl))
- .isEqualTo(suggestedCrops.get(PORTRAIT));
+ .isEqualTo(suggestedCrops.get(ORIENTATION_PORTRAIT));
assertThat(mWallpaperCropper.getCrop(
new Point(500, 800), bitmapSize, suggestedCrops, rtl))
.isEqualTo(new Rect(0, 0, 500, 800));
@@ -440,8 +441,8 @@ public class WallpaperCropperTest {
Point landscape = new Point(PORTRAIT_ONE.y, PORTRAIT_ONE.x);
Point squarePortrait = SQUARE_PORTRAIT_ONE;
Point squareLandscape = new Point(SQUARE_PORTRAIT_ONE.y, SQUARE_PORTRAIT_ONE.y);
- suggestedCrops.put(PORTRAIT, centerOf(bitmapRect, portrait));
- suggestedCrops.put(SQUARE_LANDSCAPE, centerOf(bitmapRect, squareLandscape));
+ suggestedCrops.put(ORIENTATION_PORTRAIT, centerOf(bitmapRect, portrait));
+ suggestedCrops.put(ORIENTATION_SQUARE_LANDSCAPE, centerOf(bitmapRect, squareLandscape));
for (boolean rtl : List.of(false, true)) {
assertThat(mWallpaperCropper.getCrop(
landscape, bitmapSize, suggestedCrops, rtl))
diff --git a/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java b/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java
index e97b48cb3489..24bf6ca507e6 100644
--- a/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java
@@ -16,6 +16,8 @@
package com.android.server.security.advancedprotection;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
@@ -28,15 +30,20 @@ import android.os.RemoteException;
import android.os.test.FakePermissionEnforcer;
import android.os.test.TestLooper;
import android.provider.Settings;
+import android.security.advancedprotection.AdvancedProtectionFeature;
import android.security.advancedprotection.IAdvancedProtectionCallback;
+import androidx.annotation.NonNull;
+
import com.android.server.security.advancedprotection.features.AdvancedProtectionHook;
+import com.android.server.security.advancedprotection.features.AdvancedProtectionProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@SuppressLint("VisibleForTests")
@@ -47,6 +54,7 @@ public class AdvancedProtectionServiceTest {
private Context mContext;
private AdvancedProtectionService.AdvancedProtectionStore mStore;
private TestLooper mLooper;
+ AdvancedProtectionFeature mFeature = new AdvancedProtectionFeature("test-id");
@Before
public void setup() throws Settings.SettingNotFoundException {
@@ -70,8 +78,9 @@ public class AdvancedProtectionServiceTest {
};
mLooper = new TestLooper();
+
mService = new AdvancedProtectionService(mContext, mStore, mLooper.getLooper(),
- mPermissionEnforcer, null);
+ mPermissionEnforcer, null, null);
}
@Test
@@ -93,6 +102,12 @@ public class AdvancedProtectionServiceTest {
AtomicBoolean callbackCaptor = new AtomicBoolean(false);
AdvancedProtectionHook hook =
new AdvancedProtectionHook(mContext, true) {
+ @NonNull
+ @Override
+ public AdvancedProtectionFeature getFeature() {
+ return mFeature;
+ }
+
@Override
public boolean isAvailable() {
return true;
@@ -105,7 +120,7 @@ public class AdvancedProtectionServiceTest {
};
mService = new AdvancedProtectionService(mContext, mStore, mLooper.getLooper(),
- mPermissionEnforcer, hook);
+ mPermissionEnforcer, hook, null);
mService.setAdvancedProtectionEnabled(true);
mLooper.dispatchNext();
@@ -117,6 +132,12 @@ public class AdvancedProtectionServiceTest {
AtomicBoolean callbackCalledCaptor = new AtomicBoolean(false);
AdvancedProtectionHook hook =
new AdvancedProtectionHook(mContext, true) {
+ @NonNull
+ @Override
+ public AdvancedProtectionFeature getFeature() {
+ return mFeature;
+ }
+
@Override
public boolean isAvailable() {
return false;
@@ -129,7 +150,8 @@ public class AdvancedProtectionServiceTest {
};
mService = new AdvancedProtectionService(mContext, mStore, mLooper.getLooper(),
- mPermissionEnforcer, hook);
+ mPermissionEnforcer, hook, null);
+
mService.setAdvancedProtectionEnabled(true);
mLooper.dispatchNext();
assertFalse(callbackCalledCaptor.get());
@@ -140,6 +162,12 @@ public class AdvancedProtectionServiceTest {
AtomicBoolean callbackCalledCaptor = new AtomicBoolean(false);
AdvancedProtectionHook hook =
new AdvancedProtectionHook(mContext, true) {
+ @NonNull
+ @Override
+ public AdvancedProtectionFeature getFeature() {
+ return mFeature;
+ }
+
@Override
public boolean isAvailable() {
return true;
@@ -152,7 +180,7 @@ public class AdvancedProtectionServiceTest {
};
mService = new AdvancedProtectionService(mContext, mStore, mLooper.getLooper(),
- mPermissionEnforcer, hook);
+ mPermissionEnforcer, hook, null);
mService.setAdvancedProtectionEnabled(true);
mLooper.dispatchNext();
assertTrue(callbackCalledCaptor.get());
@@ -208,6 +236,66 @@ public class AdvancedProtectionServiceTest {
assertFalse(callbackCalledCaptor.get());
}
+ @Test
+ public void testGetFeatures() {
+ AdvancedProtectionFeature feature1 = new AdvancedProtectionFeature("id-1");
+ AdvancedProtectionFeature feature2 = new AdvancedProtectionFeature("id-2");
+ AdvancedProtectionHook hook = new AdvancedProtectionHook(mContext, true) {
+ @NonNull
+ @Override
+ public AdvancedProtectionFeature getFeature() {
+ return feature1;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+ };
+
+ AdvancedProtectionProvider provider = new AdvancedProtectionProvider() {
+ @Override
+ public List<AdvancedProtectionFeature> getFeatures() {
+ return List.of(feature2);
+ }
+ };
+
+ mService = new AdvancedProtectionService(mContext, mStore, mLooper.getLooper(),
+ mPermissionEnforcer, hook, provider);
+ List<AdvancedProtectionFeature> features = mService.getAdvancedProtectionFeatures();
+ assertThat(features, containsInAnyOrder(feature1, feature2));
+ }
+
+ @Test
+ public void testGetFeatures_featureNotAvailable() {
+ AdvancedProtectionFeature feature1 = new AdvancedProtectionFeature("id-1");
+ AdvancedProtectionFeature feature2 = new AdvancedProtectionFeature("id-2");
+ AdvancedProtectionHook hook = new AdvancedProtectionHook(mContext, true) {
+ @NonNull
+ @Override
+ public AdvancedProtectionFeature getFeature() {
+ return feature1;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return false;
+ }
+ };
+
+ AdvancedProtectionProvider provider = new AdvancedProtectionProvider() {
+ @Override
+ public List<AdvancedProtectionFeature> getFeatures() {
+ return List.of(feature2);
+ }
+ };
+
+ mService = new AdvancedProtectionService(mContext, mStore, mLooper.getLooper(),
+ mPermissionEnforcer, hook, provider);
+ List<AdvancedProtectionFeature> features = mService.getAdvancedProtectionFeatures();
+ assertThat(features, containsInAnyOrder(feature2));
+ }
+
@Test
public void testSetProtection_withoutPermission() {
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 ac021e122998..cbfdc5f61e3f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -2895,6 +2895,44 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
+ android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST})
+ public void testRemoveScheduledForceGroup_onNotificationCanceled() throws Exception {
+ NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, "tag", null,
+ false);
+ when(mGroupHelper.onNotificationPosted(any(), anyBoolean())).thenReturn(false);
+ mService.addEnqueuedNotification(r);
+ NotificationManagerService.PostNotificationRunnable runnable =
+ mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
+ r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
+ runnable.run();
+ waitForIdle();
+
+ // Post an update to the notification
+ NotificationRecord r_update =
+ generateNotificationRecord(mTestNotificationChannel, 0, "tag", null, false);
+ mService.addEnqueuedNotification(r_update);
+ runnable = mService.new PostNotificationRunnable(r_update.getKey(),
+ r_update.getSbn().getPackageName(), r_update.getUid(),
+ mPostNotificationTrackerFactory.newTracker(null));
+ runnable.run();
+ waitForIdle();
+
+ // Cancel the notification
+ mBinderService.cancelNotificationWithTag(r.getSbn().getPackageName(),
+ r.getSbn().getPackageName(), r.getSbn().getTag(),
+ r.getSbn().getId(), r.getSbn().getUserId());
+ waitForIdle();
+
+ mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME);
+ waitForIdle();
+
+ // Check that onNotificationPostedWithDelay was canceled
+ verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean());
+ verify(mGroupHelper, never()).onNotificationPostedWithDelay(any(), any(), any());
+ }
+
+ @Test
@EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
public void testEnqueueNotification_forceGrouped_clearsSummaryFlag() throws Exception {
final String originalGroupName = "originalGroup";
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
index 8aa8a84206e2..093359042a3e 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -59,7 +59,7 @@ import android.os.test.TestLooper;
import android.os.vibrator.Flags;
import android.os.vibrator.PrebakedSegment;
import android.os.vibrator.PrimitiveSegment;
-import android.os.vibrator.PwleSegment;
+import android.os.vibrator.PwlePoint;
import android.os.vibrator.RampSegment;
import android.os.vibrator.StepSegment;
import android.os.vibrator.VibrationConfig;
@@ -888,7 +888,7 @@ public class VibrationThreadTest {
fakeVibrator.setMinEnvelopeEffectControlPointDurationMillis(20);
VibrationEffect effect = VibrationEffect.startWaveformEnvelope()
- .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20)
+ .addControlPoint(/*amplitude=*/ 0.1f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20)
.addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 30)
.addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 20)
.addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 30)
@@ -902,20 +902,47 @@ public class VibrationThreadTest {
verifyCallbacksTriggered(vibration, Status.FINISHED);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(
- expectedPwle(/* startAmplitude= */ 0.0f, /* endAmplitude= */ 0.0f,
- /* startFrequencyHz= */ 60f, /* endFrequencyHz= */ 60f,
- /* duration= */ 20),
- expectedPwle(/* startAmplitude= */ 0.0f, /* endAmplitude= */ 0.3f,
- /* startFrequencyHz= */ 60f, /* endFrequencyHz= */ 100f,
- /* duration= */ 30),
- expectedPwle(/* startAmplitude= */ 0.3f, /* endAmplitude= */ 0.4f,
- /* startFrequencyHz= */ 100f, /* endFrequencyHz= */ 120f,
- /* duration= */ 20),
- expectedPwle(/* startAmplitude= */ 0.4f, /* endAmplitude= */ 0.0f,
- /* startFrequencyHz= */ 120f, /* endFrequencyHz= */ 120f,
- /* duration= */ 30)
- ),
- fakeVibrator.getEffectSegments(vibration.id));
+ expectedPwle(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 0),
+ expectedPwle(/*amplitude=*/ 0.1f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20),
+ expectedPwle(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 30),
+ expectedPwle(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 20),
+ expectedPwle(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 30)
+ ), fakeVibrator.getEffectPwlePoints(vibration.id));
+
+ }
+
+ @Test
+ @EnableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+ public void vibrate_singleVibratorPwle_withInitialFrequency_runsComposePwleV2() {
+ FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
+ fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2);
+ fakeVibrator.setResonantFrequency(150);
+ fakeVibrator.setFrequenciesHz(new float[]{30f, 50f, 100f, 120f, 150f});
+ fakeVibrator.setOutputAccelerationsGs(new float[]{0.3f, 0.5f, 1.0f, 0.8f, 0.6f});
+ fakeVibrator.setMaxEnvelopeEffectSize(10);
+ fakeVibrator.setMinEnvelopeEffectControlPointDurationMillis(20);
+
+ VibrationEffect effect = VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 30)
+ .addControlPoint(/*amplitude=*/ 0.1f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20)
+ .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 30)
+ .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 20)
+ .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 30)
+ .build();
+ HalVibration vibration = startThreadAndDispatcher(effect);
+ waitForCompletion();
+
+ verify(mManagerHooks).noteVibratorOn(eq(UID), eq(100L));
+ verify(mManagerHooks).noteVibratorOff(eq(UID));
+ verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibration.id));
+ verifyCallbacksTriggered(vibration, Status.FINISHED);
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
+ assertEquals(Arrays.asList(
+ expectedPwle(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 30f, /*timeMillis=*/ 0),
+ expectedPwle(/*amplitude=*/ 0.1f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20),
+ expectedPwle(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 30),
+ expectedPwle(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 20),
+ expectedPwle(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 30)
+ ), fakeVibrator.getEffectPwlePoints(vibration.id));
}
@@ -2013,10 +2040,8 @@ public class VibrationThreadTest {
duration);
}
- private VibrationEffectSegment expectedPwle(float startAmplitude, float endAmplitude,
- float startFrequencyHz, float endFrequencyHz, int duration) {
- return new PwleSegment(startAmplitude, endAmplitude, startFrequencyHz, endFrequencyHz,
- duration);
+ private PwlePoint expectedPwle(float amplitude, float frequencyHz, int timeMillis) {
+ return new PwlePoint(amplitude, frequencyHz, timeMillis);
}
private List<Float> expectedAmplitudes(int... amplitudes) {
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerTest.java
index bc8db3be5f27..0978f48491cc 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerTest.java
@@ -44,7 +44,7 @@ import android.os.VibratorInfo;
import android.os.test.TestLooper;
import android.os.vibrator.PrebakedSegment;
import android.os.vibrator.PrimitiveSegment;
-import android.os.vibrator.PwleSegment;
+import android.os.vibrator.PwlePoint;
import android.os.vibrator.RampSegment;
import androidx.test.InstrumentationRegistry;
@@ -274,9 +274,9 @@ public class VibratorControllerTest {
when(mNativeWrapperMock.composePwleV2(any(), anyLong())).thenReturn(15L);
VibratorController controller = createController();
- PwleSegment[] primitives = new PwleSegment[]{
- new PwleSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 1,
- /* startFrequencyHz= */ 100, /* endFrequencyHz= */ 200, /* duration= */ 10)
+ PwlePoint[] primitives = new PwlePoint[]{
+ new PwlePoint(/*amplitude=*/ 0, /*frequencyHz=*/ 100, /*timeMillis=*/ 0),
+ new PwlePoint(/*amplitude=*/ 1, /*frequencyHz=*/ 200, /*timeMillis=*/ 10)
};
assertEquals(15L, controller.on(primitives, 12));
assertTrue(controller.isVibrating());
diff --git a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorControllerProvider.java b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorControllerProvider.java
index 2c3e9b29d11f..4dc59c20c431 100644
--- a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorControllerProvider.java
+++ b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorControllerProvider.java
@@ -26,7 +26,7 @@ import android.os.VibrationEffect;
import android.os.VibratorInfo;
import android.os.vibrator.PrebakedSegment;
import android.os.vibrator.PrimitiveSegment;
-import android.os.vibrator.PwleSegment;
+import android.os.vibrator.PwlePoint;
import android.os.vibrator.RampSegment;
import android.os.vibrator.StepSegment;
import android.os.vibrator.VibrationEffectSegment;
@@ -50,6 +50,7 @@ public final class FakeVibratorControllerProvider {
private final Map<Long, PrebakedSegment> mEnabledAlwaysOnEffects = new HashMap<>();
private final Map<Long, List<VibrationEffectSegment>> mEffectSegments = new TreeMap<>();
private final Map<Long, List<VibrationEffect.VendorEffect>> mVendorEffects = new TreeMap<>();
+ private final Map<Long, List<PwlePoint>> mEffectPwlePoints = new TreeMap<>();
private final Map<Long, List<Integer>> mBraking = new HashMap<>();
private final List<Float> mAmplitudes = new ArrayList<>();
private final List<Boolean> mExternalControlStates = new ArrayList<>();
@@ -91,6 +92,10 @@ public final class FakeVibratorControllerProvider {
mVendorEffects.computeIfAbsent(vibrationId, k -> new ArrayList<>()).add(vendorEffect);
}
+ void recordEffectPwlePoint(long vibrationId, PwlePoint pwlePoint) {
+ mEffectPwlePoints.computeIfAbsent(vibrationId, k -> new ArrayList<>()).add(pwlePoint);
+ }
+
void recordBraking(long vibrationId, int braking) {
mBraking.computeIfAbsent(vibrationId, k -> new ArrayList<>()).add(braking);
}
@@ -195,11 +200,11 @@ public final class FakeVibratorControllerProvider {
}
@Override
- public long composePwleV2(PwleSegment[] primitives, long vibrationId) {
+ public long composePwleV2(PwlePoint[] pwlePoints, long vibrationId) {
long duration = 0;
- for (PwleSegment primitive: primitives) {
- duration += primitive.getDuration();
- recordEffectSegment(vibrationId, primitive);
+ for (PwlePoint pwlePoint: pwlePoints) {
+ duration += pwlePoint.getTimeMillis();
+ recordEffectPwlePoint(vibrationId, pwlePoint);
}
applyLatency(mOnLatency);
scheduleListener(duration, vibrationId);
@@ -482,6 +487,28 @@ public final class FakeVibratorControllerProvider {
return result;
}
+ /** Return list of {@link PwlePoint} played by this controller, in order. */
+ public List<PwlePoint> getEffectPwlePoints(long vibrationId) {
+ if (mEffectPwlePoints.containsKey(vibrationId)) {
+ return new ArrayList<>(mEffectPwlePoints.get(vibrationId));
+ } else {
+ return new ArrayList<>();
+ }
+ }
+
+ /**
+ * Returns a list of all vibrations' {@link PwlePoint}s, for external-use where vibration
+ * IDs aren't exposed.
+ */
+ public List<PwlePoint> getAllEffectPwlePoints() {
+ // Returns segments in order of vibrationId, which increases over time. TreeMap gives order.
+ ArrayList<PwlePoint> result = new ArrayList<>();
+ for (List<PwlePoint> subList : mEffectPwlePoints.values()) {
+ result.addAll(subList);
+ }
+ return result;
+ }
+
/** Return list of states set for external control to the fake vibrator hardware. */
public List<Boolean> getExternalControlStates() {
return mExternalControlStates;
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 b8cfa7c39464..00c9691835db 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
@@ -259,6 +259,10 @@ class AppCompatActivityRobot {
doReturn(embedded).when(mActivityStack.top()).isEmbedded();
}
+ void setTopActivityHasLetterboxedBounds(boolean letterboxed) {
+ doReturn(letterboxed).when(mActivityStack.top()).areBoundsLetterboxed();
+ }
+
void setTopActivityVisible(boolean isVisible) {
doReturn(isVisible).when(mActivityStack.top()).isVisible();
}
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 5187f87cd6db..42752c326615 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransparentPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransparentPolicyTest.java
@@ -217,6 +217,19 @@ public class TransparentPolicyTest extends WindowTestsBase {
});
}
+ @Test
+ public void testNotApplyStrategyToTranslucentActivitiesOverNotLetterboxedActivities() {
+ runTestScenario((robot) -> {
+ robot.transparentActivity((ta) -> {
+ ta.activity().setTopActivityHasLetterboxedBounds(false);
+ ta.launchTransparentActivityInTask();
+
+ ta.checkTopActivityTransparentPolicyStartNotInvoked();
+ ta.checkTopActivityTransparentPolicyStateIsRunning(/* running */ false);
+ });
+ });
+ }
+
@EnableFlags(com.android.window.flags.Flags.FLAG_RESPECT_NON_TOP_VISIBLE_FIXED_ORIENTATION)
@Test
public void testNotRunStrategyToTranslucentActivitiesIfRespectOrientation() {
@@ -388,6 +401,7 @@ public class TransparentPolicyTest extends WindowTestsBase {
mTransparentActivityRobot = new AppCompatTransparentActivityRobot(activity());
// We always create at least an opaque activity in a Task
activity().createNewTaskWithBaseActivity();
+ activity().setTopActivityHasLetterboxedBounds(true);
}
@Override
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index e332d0f720e8..be02232abe1b 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -26,6 +26,7 @@ import android.annotation.Nullable;
import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
@@ -39,6 +40,7 @@ import android.telephony.SubscriptionManager;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.TelephonyManager;
+import android.telephony.TelephonyRegistryManager;
import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.ITelephony;
@@ -61,13 +63,19 @@ import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
- * Manages satellite operations such as provisioning, pointing, messaging, location sharing, etc.
- * To get the object, call {@link Context#getSystemService(String)}.
+ * Manages satellite states such as monitoring enabled state and operations such as provisioning,
+ * pointing, messaging, location sharing, etc.
*
- * @hide
+ * <p>To get the object, call {@link Context#getSystemService(String)} with
+ * {@link Context#SATELLITE_SERVICE}.
+ *
+ * <p>SatelliteManager is intended for use on devices with feature
+ * {@link PackageManager#FEATURE_TELEPHONY_SATELLITE}. On devices without the feature, the behavior
+ * is not reliable.
*/
+@SystemService(Context.SATELLITE_SERVICE)
+@FlaggedApi(Flags.FLAG_SATELLITE_STATE_CHANGE_LISTENER)
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SATELLITE)
-@SystemApi
public final class SatelliteManager {
private static final String TAG = "SatelliteManager";
@@ -103,6 +111,8 @@ public final class SatelliteManager {
*/
@Nullable private final Context mContext;
+ private TelephonyRegistryManager mTelephonyRegistryMgr;
+
/**
* Create an instance of the SatelliteManager.
*
@@ -736,6 +746,65 @@ public final class SatelliteManager {
"android.telephony.METADATA_SATELLITE_MANUAL_CONNECT_P2P_SUPPORT";
/**
+ * Registers a {@link SatelliteStateChangeListener} to receive callbacks when the satellite
+ * state may have changed.
+ *
+ * <p>The callback method is immediately triggered with latest state on invoking this method if
+ * the state change has been notified before.
+ *
+ * @param executor The {@link Executor} where the {@code listener} will be invoked
+ * @param listener The listener to monitor the satellite state change
+ *
+ * @see SatelliteStateChangeListener
+ * @see TelephonyManager#hasCarrierPrivileges()
+ */
+ @FlaggedApi(Flags.FLAG_SATELLITE_STATE_CHANGE_LISTENER)
+ @RequiresPermission(anyOf = {android.Manifest.permission.READ_BASIC_PHONE_STATE,
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PHONE_STATE,
+ "carrier privileges"})
+ public void registerStateChangeListener(@NonNull @CallbackExecutor Executor executor,
+ @NonNull SatelliteStateChangeListener listener) {
+ if (mContext == null) {
+ throw new IllegalStateException("Telephony service is null");
+ }
+
+ mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);
+ if (mTelephonyRegistryMgr == null) {
+ throw new IllegalStateException("Telephony registry service is null");
+ }
+ mTelephonyRegistryMgr.addSatelliteStateChangeListener(executor, listener);
+ }
+
+ /**
+ * Unregisters the {@link SatelliteStateChangeListener} previously registered with
+ * {@link #registerStateChangeListener(Executor, SatelliteStateChangeListener)}.
+ *
+ * <p>It will be a no-op if the {@code listener} is not currently registered.
+ *
+ * @param listener The listener to unregister
+ *
+ * @see SatelliteStateChangeListener
+ * @see TelephonyManager#hasCarrierPrivileges()
+ */
+ @FlaggedApi(Flags.FLAG_SATELLITE_STATE_CHANGE_LISTENER)
+ @RequiresPermission(anyOf = {android.Manifest.permission.READ_BASIC_PHONE_STATE,
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PHONE_STATE,
+ "carrier privileges"})
+ public void unregisterStateChangeListener(@NonNull SatelliteStateChangeListener listener) {
+ if (mContext == null) {
+ throw new IllegalStateException("Telephony service is null");
+ }
+
+ mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);
+ if (mTelephonyRegistryMgr == null) {
+ throw new IllegalStateException("Telephony registry service is null");
+ }
+ mTelephonyRegistryMgr.removeSatelliteStateChangeListener(listener);
+ }
+
+ /**
* Request to enable or disable the satellite modem and demo mode.
* If satellite modem and cellular modem cannot work concurrently,
* then this will disable the cellular modem if satellite modem is enabled,
diff --git a/telephony/java/android/telephony/satellite/SatelliteStateChangeListener.java b/telephony/java/android/telephony/satellite/SatelliteStateChangeListener.java
new file mode 100644
index 000000000000..3aa910dfcc80
--- /dev/null
+++ b/telephony/java/android/telephony/satellite/SatelliteStateChangeListener.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.satellite;
+
+import android.annotation.FlaggedApi;
+
+import com.android.internal.telephony.flags.Flags;
+
+import java.util.concurrent.Executor;
+
+/**
+ * A listener interface to monitor satellite state change events.
+ *
+ * <p>Call
+ * {@link SatelliteManager#registerStateChangeListener(Executor, SatelliteStateChangeListener)}
+ * to monitor. Call
+ * {@link SatelliteManager#unregisterStateChangeListener(SatelliteStateChangeListener)} to cancel.
+ *
+ * @see SatelliteManager#registerStateChangeListener(Executor, SatelliteStateChangeListener)
+ * @see SatelliteManager#unregisterStateChangeListener(SatelliteStateChangeListener)
+ */
+@FlaggedApi(Flags.FLAG_SATELLITE_STATE_CHANGE_LISTENER)
+public interface SatelliteStateChangeListener {
+ /**
+ * Called when satellite modem enabled state may have changed.
+ *
+ * <p>Note:there is no guarantee that this callback will only be invoked upon a change of state.
+ * In other word, in some cases, the callback may report with the same enabled states. It is the
+ * caller's responsibility to filter uninterested states.
+ *
+ * <p>Note:satellite enabled state is a device state that is NOT associated with subscription or
+ * SIM slot.
+ *
+ * @param isEnabled {@code true} means satellite modem is enabled.
+ */
+ void onEnabledStateChanged(boolean isEnabled);
+}
diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
index a7e22141e56f..0b147d63ed08 100644
--- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
@@ -22,8 +22,10 @@ import android.content.pm.PackageManager
import android.content.res.Resources
import android.hardware.input.IInputManager
import android.hardware.input.AidlKeyGestureEvent
+import android.hardware.input.AppLaunchData
import android.hardware.input.IKeyGestureEventListener
import android.hardware.input.IKeyGestureHandler
+import android.hardware.input.InputGestureData
import android.hardware.input.InputManager
import android.hardware.input.InputManagerGlobal
import android.hardware.input.KeyGestureEvent
@@ -232,7 +234,7 @@ class KeyGestureControllerTests {
keyGestureController.handleKeyGesture(/* deviceId = */ 0, intArrayOf(KeyEvent.KEYCODE_HOME),
/* modifierState = */ 0, KeyGestureEvent.KEY_GESTURE_TYPE_HOME,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, /* displayId */ 0,
- /* focusedToken = */ null, /* flags = */ 0
+ /* focusedToken = */ null, /* flags = */ 0, /* appLaunchData = */null
)
assertEquals(
@@ -259,6 +261,7 @@ class KeyGestureControllerTests {
val expectedKeys: IntArray,
val expectedModifierState: Int,
val expectedActions: IntArray,
+ val expectedAppLaunchData: AppLaunchData? = null,
) {
override fun toString(): String = name
}
@@ -1055,6 +1058,62 @@ class KeyGestureControllerTests {
testKeyGestureInternal(keyGestureController, test)
}
+ @Keep
+ private fun customInputGesturesTestArguments(): Array<TestData> {
+ return arrayOf(
+ TestData(
+ "META + ALT + Q -> Go Home",
+ intArrayOf(
+ KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_ALT_LEFT,
+ KeyEvent.KEYCODE_Q
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_HOME,
+ intArrayOf(KeyEvent.KEYCODE_Q),
+ KeyEvent.META_META_ON or KeyEvent.META_ALT_ON,
+ intArrayOf(
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE
+ )
+ ),
+ TestData(
+ "META + ALT + Q -> Launch app",
+ intArrayOf(
+ KeyEvent.KEYCODE_CTRL_LEFT,
+ KeyEvent.KEYCODE_SHIFT_LEFT,
+ KeyEvent.KEYCODE_Q
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+ intArrayOf(KeyEvent.KEYCODE_Q),
+ KeyEvent.META_CTRL_ON or KeyEvent.META_SHIFT_ON,
+ intArrayOf(
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE
+ ),
+ AppLaunchData.createLaunchDataForComponent("com.test", "com.test.BookmarkTest")
+ ),
+ )
+ }
+
+ @Test
+ @Parameters(method = "customInputGesturesTestArguments")
+ fun testCustomKeyGestures(test: TestData) {
+ val keyGestureController = KeyGestureController(context, testLooper.looper)
+ val builder = InputGestureData.Builder()
+ .setKeyGestureType(test.expectedKeyGestureType)
+ .setTrigger(
+ InputGestureData.createKeyTrigger(
+ test.expectedKeys[0],
+ test.expectedModifierState
+ )
+ );
+ if (test.expectedAppLaunchData != null) {
+ builder.setAppLaunchData(test.expectedAppLaunchData)
+ }
+ val inputGestureData = builder.build();
+
+ keyGestureController.addCustomInputGesture(0, inputGestureData.aidlData)
+ testKeyGestureInternal(keyGestureController, test)
+ }
+
private fun testKeyGestureInternal(keyGestureController: KeyGestureController, test: TestData) {
var handleEvents = mutableListOf<KeyGestureEvent>()
val handler = KeyGestureHandler { event, _ ->
@@ -1093,6 +1152,11 @@ class KeyGestureControllerTests {
test.expectedActions[i],
event.action
)
+ assertEquals(
+ "Test: $test doesn't produce correct app launch data",
+ test.expectedAppLaunchData,
+ event.appLaunchData
+ )
}
keyGestureController.unregisterKeyGestureHandler(handler, 0)
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
index 22858803b597..108942ee754a 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
@@ -368,7 +368,7 @@ object ProtoLogTool {
}
interface ProtologViewerConfigBuilder {
- fun build(statements: Map<LogCall, Long>): ByteArray
+ fun build(groups: Collection<LogGroup>, statements: Map<LogCall, Long>): ByteArray
}
private fun viewerConf(command: CommandOptions) {
@@ -416,7 +416,7 @@ object ProtoLogTool {
}
val outFile = injector.fileOutputStream(command.viewerConfigFileNameArg)
- outFile.write(configBuilder.build(logCallRegistry.getStatements()))
+ outFile.write(configBuilder.build(groups.values, logCallRegistry.getStatements()))
outFile.close()
}
diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigJsonBuilder.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigJsonBuilder.kt
index 7714db212c9f..16a3d7cdda21 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigJsonBuilder.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigJsonBuilder.kt
@@ -21,8 +21,7 @@ import com.android.protolog.tool.Constants.VERSION
import java.io.StringWriter
class ViewerConfigJsonBuilder : ProtoLogTool.ProtologViewerConfigBuilder {
- override fun build(statements: Map<ProtoLogTool.LogCall, Long>): ByteArray {
- val groups = statements.map { it.key.logGroup }.toSet()
+ override fun build(groups: Collection<LogGroup>, statements: Map<ProtoLogTool.LogCall, Long>): ByteArray {
val stringWriter = StringWriter()
val writer = JsonWriter(stringWriter)
writer.setIndent(" ")
diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt
index 245e802df49b..de85411e4ffc 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt
@@ -28,10 +28,14 @@ class ViewerConfigProtoBuilder : ProtoLogTool.ProtologViewerConfigBuilder {
* @return a byte array of a ProtoLogViewerConfig proto message encoding all the viewer
* configurations mapping protolog hashes to message information and log group information.
*/
- override fun build(statements: Map<ProtoLogTool.LogCall, Long>): ByteArray {
+ override fun build(groups: Collection<LogGroup>, statements: Map<ProtoLogTool.LogCall, Long>): ByteArray {
val configBuilder = ProtoLogViewerConfig.newBuilder()
- val groups = statements.map { it.key.logGroup }.toSet()
+ // TODO(b/373754057): We are passing all the groups now, because some groups might only be
+ // used by Kotlin code that is not processed, but for group that get enabled to log to
+ // logcat we try and load the viewer configurations for this group, so the group must exist
+ // in the viewer config. Once Kotlin is pre-processed or this logic changes we should only
+ // use the groups that are actually used as an optimization.
val groupIds = mutableMapOf<LogGroup, Int>()
groups.forEach {
groupIds.putIfAbsent(it, groupIds.size + 1)
diff --git a/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigJsonBuilderTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigJsonBuilderTest.kt
index d27ae88fc488..1a20d4c5bad6 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigJsonBuilderTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigJsonBuilderTest.kt
@@ -36,6 +36,8 @@ class ViewerConfigJsonBuilderTest {
private val GROUP_DISABLED = LogGroup("DEBUG_GROUP", false, true, TAG2)
private val GROUP_TEXT_DISABLED = LogGroup("DEBUG_GROUP", true, false, TAG2)
private const val PATH = "/tmp/test.java"
+
+ private val GROUPS = listOf(GROUP1, GROUP2, GROUP3)
}
private val configBuilder = ViewerConfigJsonBuilder()
@@ -53,7 +55,7 @@ class ViewerConfigJsonBuilderTest {
LogCall(TEST3.messageString, LogLevel.ERROR, GROUP3, PATH)))
val parsedConfig = parseConfig(
- configBuilder.build(logCallRegistry.getStatements()).toString(Charsets.UTF_8))
+ configBuilder.build(GROUPS, logCallRegistry.getStatements()).toString(Charsets.UTF_8))
assertEquals(3, parsedConfig.size)
assertEquals(TEST1, parsedConfig[CodeUtils.hash(PATH,
TEST1.messageString, LogLevel.INFO, GROUP1)])
@@ -72,7 +74,7 @@ class ViewerConfigJsonBuilderTest {
LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH)))
val parsedConfig = parseConfig(
- configBuilder.build(logCallRegistry.getStatements()).toString(Charsets.UTF_8))
+ configBuilder.build(GROUPS, logCallRegistry.getStatements()).toString(Charsets.UTF_8))
assertEquals(1, parsedConfig.size)
assertEquals(TEST1, parsedConfig[CodeUtils.hash(PATH, TEST1.messageString,
LogLevel.INFO, GROUP1)])
diff --git a/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigProtoBuilderTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigProtoBuilderTest.kt
new file mode 100644
index 000000000000..74a8de7f70c0
--- /dev/null
+++ b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigProtoBuilderTest.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.protolog.tool
+
+import com.android.internal.protolog.common.LogLevel
+import com.android.protolog.tool.ProtoLogTool.LogCall
+import com.google.common.truth.Truth
+import org.junit.Test
+import perfetto.protos.PerfettoTrace.ProtoLogViewerConfig
+
+class ViewerConfigProtoBuilderTest {
+ companion object {
+ private val TAG1 = "WM_TEST"
+ private val TAG2 = "WM_DEBUG"
+
+ private val TEST1 = ViewerConfigParser.ConfigEntry("test1", LogLevel.INFO.name,
+ TAG1
+ )
+ private val TEST2 = ViewerConfigParser.ConfigEntry("test2", LogLevel.DEBUG.name,
+ TAG2
+ )
+
+ private val GROUP1 = LogGroup("TEST_GROUP", true, true, TAG1)
+ private val GROUP2 = LogGroup("DEBUG_GROUP", true, true, TAG2)
+ private val GROUP3 = LogGroup("UNUSED_GROUP", true, true, TAG1)
+
+ private val GROUPS = listOf(
+ GROUP1,
+ GROUP2,
+ GROUP3
+ )
+
+ private const val PATH = "/tmp/test.java"
+ }
+
+ @Test
+ fun includesUnusedProtoLogGroups() {
+ // Added because of b/373754057. This test might need to be removed in the future.
+
+ val configBuilder = ViewerConfigProtoBuilder()
+
+ val logCallRegistry = ProtoLogTool.LogCallRegistry()
+ logCallRegistry.addLogCalls(listOf(
+ LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH),
+ LogCall(TEST2.messageString, LogLevel.INFO, GROUP2, PATH),
+ ))
+
+ val rawProto = configBuilder.build(GROUPS, logCallRegistry.getStatements())
+
+ val viewerConfig = ProtoLogViewerConfig.parseFrom(rawProto)
+ Truth.assertThat(viewerConfig.groupsCount).isEqualTo(GROUPS.size)
+ Truth.assertThat(viewerConfig.messagesCount).isLessThan(GROUPS.size)
+ }
+} \ No newline at end of file