summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java14
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java73
-rw-r--r--cmds/incidentd/src/Section.cpp2
-rw-r--r--core/java/android/app/Activity.java5
-rw-r--r--core/java/android/app/ActivityThread.java25
-rw-r--r--core/java/android/app/ComponentOptions.java6
-rw-r--r--core/java/android/companion/virtual/IVirtualDeviceManager.aidl14
-rw-r--r--core/java/android/companion/virtual/VirtualDeviceManager.java35
-rw-r--r--core/java/android/content/Context.java2
-rw-r--r--core/java/android/content/pm/ActivityInfo.java20
-rw-r--r--core/java/android/hardware/display/DisplayManager.java14
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java26
-rw-r--r--core/java/android/hardware/display/DisplayManagerInternal.java9
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl5
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java19
-rw-r--r--core/java/android/net/VpnManager.java6
-rw-r--r--core/java/android/nfc/INfcTag.aidl1
-rw-r--r--core/java/android/nfc/Tag.java23
-rw-r--r--core/java/android/provider/Settings.java11
-rw-r--r--core/java/android/service/dreams/DreamService.java22
-rw-r--r--core/java/android/view/FrameMetrics.java5
-rw-r--r--core/java/android/view/IWindowManager.aidl15
-rw-r--r--core/java/android/view/InputWindowHandle.java1
-rw-r--r--core/java/android/view/InsetsSourceConsumer.java37
-rw-r--r--core/java/android/view/SurfaceView.java9
-rw-r--r--core/java/android/view/View.java4
-rw-r--r--core/java/android/view/autofill/AutofillManager.java77
-rw-r--r--core/java/android/view/autofill/IAutoFillManager.aidl2
-rw-r--r--core/java/android/view/translation/ViewTranslationCallback.java9
-rw-r--r--core/java/android/widget/TextView.java23
-rw-r--r--core/java/android/widget/TextViewTranslationCallback.java76
-rw-r--r--core/java/android/window/DisplayWindowPolicyController.java5
-rw-r--r--core/java/android/window/ProxyOnBackInvokedDispatcher.java17
-rw-r--r--core/java/android/window/TaskFragmentInfo.java48
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java206
-rw-r--r--core/java/com/android/internal/app/ChooserListAdapter.java38
-rw-r--r--core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java11
-rw-r--r--core/java/com/android/internal/graphics/cam/Cam.java7
-rw-r--r--core/java/com/android/internal/graphics/cam/CamUtils.java157
-rw-r--r--core/java/com/android/internal/graphics/cam/Frame.java20
-rw-r--r--core/java/com/android/internal/graphics/cam/HctSolver.java721
-rw-r--r--core/java/com/android/internal/jank/InteractionJankMonitor.java12
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java4
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBar.aidl3
-rw-r--r--core/java/com/android/internal/widget/ResolverDrawerLayout.java8
-rw-r--r--core/proto/android/server/windowmanagertransitiontrace.proto68
-rw-r--r--core/res/res/drawable-nodpi/platlogo.xml37
-rw-r--r--core/res/res/layout/log_access_user_consent_dialog_permission.xml141
-rw-r--r--core/res/res/values-ar/strings.xml2
-rw-r--r--core/res/res/values-de/strings.xml2
-rw-r--r--core/res/res/values-es-rUS/strings.xml2
-rw-r--r--core/res/res/values-gu/strings.xml2
-rw-r--r--core/res/res/values-kn/strings.xml12
-rw-r--r--core/res/res/values-ml/strings.xml2
-rw-r--r--core/res/res/values-or/strings.xml2
-rw-r--r--core/res/res/values-pt-rBR/strings.xml10
-rw-r--r--core/res/res/values-pt/strings.xml10
-rw-r--r--core/res/res/values-te/strings.xml2
-rw-r--r--core/res/res/values/config.xml13
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/tests/coretests/src/android/colormodel/CamTest.java33
-rw-r--r--data/etc/services.core.protolog.json18
-rw-r--r--graphics/java/android/graphics/Point.java12
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java9
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java52
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java186
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java46
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/AndroidManifest.xml5
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java108
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java7
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/MinimumDimensionActivity.java25
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java203
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java90
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java6
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java4
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java24
-rw-r--r--libs/WindowManager/Shell/res/values-af/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-am/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-ar/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-as/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-az/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-be/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-bg/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-bn/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-bs/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-ca/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-cs/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-da/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-de/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-el/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-es/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-et/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-eu/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-fa/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-fi/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-fr/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-gl/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-gu/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-hi/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-hr/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-hu/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-hy/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-in/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-is/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-it/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-iw/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-ja/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-ka/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-kk/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-km/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-kn/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-ko/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-ky/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-lo/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-lt/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-lv/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-mk/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-ml/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-mn/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-mr/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-ms/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-my/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-nb/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-ne/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-nl/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-or/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-pa/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-pl/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-pt/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-ro/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-ru/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-si/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-sk/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-sl/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-sq/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-sr/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-sv/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-sw/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-ta/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-te/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-th/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-tl/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-tr/strings_tv.xml16
-rw-r--r--libs/WindowManager/Shell/res/values-uk/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-ur/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-uz/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-vi/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/res/values-zu/strings_tv.xml14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java29
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java44
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithm.java97
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java23
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java57
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java58
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt66
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt113
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt18
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt44
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml26
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java23
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java7
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithmTest.java96
-rw-r--r--libs/hwui/FrameInfo.cpp34
-rw-r--r--libs/hwui/FrameInfo.h1
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp30
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h13
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp37
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.h13
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp16
-rw-r--r--libs/hwui/renderthread/IRenderPipeline.h20
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp5
-rw-r--r--libs/hwui/renderthread/VulkanManager.h4
-rw-r--r--media/java/android/media/MediaFormat.java23
-rw-r--r--media/java/android/media/audio/common/AidlConversion.java4
-rw-r--r--media/java/android/media/tv/tuner/Tuner.java8
-rw-r--r--media/jni/android_media_MediaCodec.cpp142
-rw-r--r--media/jni/android_media_MediaCodecLinearBlock.h16
-rw-r--r--packages/CompanionDeviceManager/res/values-pa/strings.xml4
-rw-r--r--packages/EasterEgg/res/drawable/android_13.xml42
-rw-r--r--packages/EasterEgg/res/drawable/android_13_mono.xml31
-rw-r--r--packages/EasterEgg/res/drawable/icon.xml3
-rw-r--r--packages/EasterEgg/res/drawable/icon_bg.xml2
-rw-r--r--packages/PackageInstaller/res/values-ar/strings.xml2
-rw-r--r--packages/PackageInstaller/res/values-bs/strings.xml6
-rw-r--r--packages/PackageInstaller/res/values-es/strings.xml8
-rw-r--r--packages/PackageInstaller/res/values-gl/strings.xml2
-rw-r--r--packages/PackageInstaller/res/values-hi/strings.xml4
-rw-r--r--packages/PackageInstaller/res/values-ja/strings.xml6
-rw-r--r--packages/PackageInstaller/res/values-km/strings.xml2
-rw-r--r--packages/PackageInstaller/res/values-ky/strings.xml6
-rw-r--r--packages/PackageInstaller/res/values-mr/strings.xml2
-rw-r--r--packages/PackageInstaller/res/values-my/strings.xml4
-rw-r--r--packages/PackageInstaller/res/values-ne/strings.xml6
-rw-r--r--packages/PackageInstaller/res/values-nl/strings.xml2
-rw-r--r--packages/PackageInstaller/res/values-or/strings.xml2
-rw-r--r--packages/PackageInstaller/res/values-pa/strings.xml2
-rw-r--r--packages/PackageInstaller/res/values-pt-rBR/strings.xml6
-rw-r--r--packages/PackageInstaller/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/PackageInstaller/res/values-pt/strings.xml6
-rw-r--r--packages/PackageInstaller/res/values-sk/strings.xml2
-rw-r--r--packages/PackageInstaller/res/values-th/strings.xml2
-rw-r--r--packages/PackageInstaller/res/values-uk/strings.xml2
-rw-r--r--packages/PackageInstaller/res/values-uz/strings.xml2
-rw-r--r--packages/PackageInstaller/res/values-zh-rCN/strings.xml2
-rw-r--r--packages/PackageInstaller/res/values-zh-rTW/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-mr/strings.xml2
-rw-r--r--packages/SettingsLib/AppPreference/res/layout/preference_app.xml2
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarDelegate.java5
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayout.java5
-rw-r--r--packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml1
-rw-r--r--packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java10
-rw-r--r--packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml2
-rw-r--r--packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_selector_with_widget.xml2
-rw-r--r--packages/SettingsLib/SettingsTheme/res/layout-v31/settingslib_preference.xml2
-rw-r--r--packages/SettingsLib/TopIntroPreference/res/layout/top_intro_preference.xml1
-rw-r--r--packages/SettingsLib/TwoTargetPreference/res/layout-v31/preference_two_target.xml2
-rw-r--r--packages/SettingsLib/res/layout/preference_access_point.xml2
-rw-r--r--packages/SettingsLib/res/layout/preference_checkable_two_target.xml2
-rw-r--r--packages/SettingsLib/res/layout/restricted_switch_preference.xml3
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-am/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-as/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-az/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-da/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-en-rCA/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-en-rXC/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-fr/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-gu/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-hu/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-is/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ka/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-km/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ky/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-lo/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-mr/arrays.xml4
-rw-r--r--packages/SettingsLib/res/values-mr/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ms/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-or/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-pa/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-pt/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-si/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sl/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-sq/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ta/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-tl/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ur/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-uz/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml1
-rw-r--r--packages/SystemUI/docs/device-entry/doze.md3
-rw-r--r--packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt96
-rw-r--r--packages/SystemUI/res-keyguard/values/strings.xml52
-rw-r--r--packages/SystemUI/res/drawable-nodpi/android_13.xml42
-rw-r--r--packages/SystemUI/res/drawable-nodpi/android_13_mono.xml31
-rw-r--r--packages/SystemUI/res/drawable-nodpi/icon.xml3
-rw-r--r--packages/SystemUI/res/drawable-nodpi/icon_bg.xml2
-rw-r--r--packages/SystemUI/res/drawable/privacy_item_circle_media_projection.xml36
-rw-r--r--packages/SystemUI/res/layout/clipboard_edit_text_activity.xml1
-rw-r--r--packages/SystemUI/res/layout/media_long_press_menu.xml4
-rw-r--r--packages/SystemUI/res/layout/media_output_list_item.xml1
-rw-r--r--packages/SystemUI/res/values-af/strings.xml5
-rw-r--r--packages/SystemUI/res/values-am/strings.xml5
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml5
-rw-r--r--packages/SystemUI/res/values-as/strings.xml5
-rw-r--r--packages/SystemUI/res/values-az/strings.xml5
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml5
-rw-r--r--packages/SystemUI/res/values-be/strings.xml5
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml5
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml5
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml15
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml5
-rw-r--r--packages/SystemUI/res/values-ca/tiles_states_strings.xml2
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml5
-rw-r--r--packages/SystemUI/res/values-da/strings.xml5
-rw-r--r--packages/SystemUI/res/values-de/strings.xml5
-rw-r--r--packages/SystemUI/res/values-el/strings.xml5
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml5
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml5
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml5
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml5
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml5
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml7
-rw-r--r--packages/SystemUI/res/values-es/strings.xml5
-rw-r--r--packages/SystemUI/res/values-es/tiles_states_strings.xml4
-rw-r--r--packages/SystemUI/res/values-et/strings.xml5
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml5
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml5
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml5
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml5
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml22
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml5
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml5
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml5
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml5
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml5
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml5
-rw-r--r--packages/SystemUI/res/values-in/strings.xml5
-rw-r--r--packages/SystemUI/res/values-is/strings.xml5
-rw-r--r--packages/SystemUI/res/values-it/strings.xml5
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml5
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml5
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml5
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml5
-rw-r--r--packages/SystemUI/res/values-km/strings.xml5
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml5
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml5
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml5
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml5
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml5
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml5
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml5
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml5
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml5
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml7
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml5
-rw-r--r--packages/SystemUI/res/values-my/strings.xml5
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml22
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml5
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml5
-rw-r--r--packages/SystemUI/res/values-or/strings.xml5
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml5
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml22
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml5
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml5
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml5
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml5
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml7
-rw-r--r--packages/SystemUI/res/values-si/strings.xml5
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml5
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml5
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml5
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml5
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml5
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml5
-rw-r--r--packages/SystemUI/res/values-sw600dp-land/dimens.xml2
-rw-r--r--packages/SystemUI/res/values-sw720dp-land/dimens.xml2
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml7
-rw-r--r--packages/SystemUI/res/values-te/strings.xml5
-rw-r--r--packages/SystemUI/res/values-th/strings.xml5
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml5
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml5
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml22
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml5
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml5
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml5
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml5
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml5
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml5
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml5
-rw-r--r--packages/SystemUI/res/values/dimens.xml12
-rw-r--r--packages/SystemUI/res/values/strings.xml75
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java9
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java14
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeLog.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeUi.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/GutsViewHolder.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java105
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControllerFactory.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaData.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt147
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaUiEventLogger.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt137
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt277
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt171
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitor.kt249
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/MediaProjectionPrivacyItemMonitor.kt202
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyConfig.kt157
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt221
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemMonitor.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyModule.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java50
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/toast/ToastUI.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/PluralMessageFormater.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java72
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java68
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt85
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt107
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitorTest.kt378
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyConfigFlagsTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt)104
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt425
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt27
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java29
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java32
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java38
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java6
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java5
-rw-r--r--services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java257
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java91
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java2
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/SaveUi.java4
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerService.java45
-rw-r--r--services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java6
-rw-r--r--services/companion/java/com/android/server/companion/AssociationStoreImpl.java16
-rw-r--r--services/companion/java/com/android/server/companion/CompanionApplicationController.java41
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java11
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java12
-rw-r--r--services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java49
-rw-r--r--services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java61
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java64
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java59
-rw-r--r--services/core/java/com/android/server/TEST_MAPPING7
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java5
-rw-r--r--services/core/java/com/android/server/adb/AdbService.java34
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java14
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java55
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java12
-rw-r--r--services/core/java/com/android/server/am/AppProfiler.java4
-rw-r--r--services/core/java/com/android/server/am/ContentProviderHelper.java23
-rw-r--r--services/core/java/com/android/server/am/HostingRecord.java29
-rw-r--r--services/core/java/com/android/server/am/ProcessProfileRecord.java114
-rw-r--r--services/core/java/com/android/server/am/ProcessServiceRecord.java29
-rw-r--r--services/core/java/com/android/server/am/ProcessStateRecord.java16
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java5
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java8
-rw-r--r--services/core/java/com/android/server/audio/PlaybackActivityMonitor.java6
-rw-r--r--services/core/java/com/android/server/biometrics/OWNERS15
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java7
-rw-r--r--services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java12
-rw-r--r--services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java33
-rw-r--r--services/core/java/com/android/server/connectivity/PacProxyService.java19
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java229
-rw-r--r--services/core/java/com/android/server/connectivity/VpnIkev2Utils.java24
-rw-r--r--services/core/java/com/android/server/display/BrightnessSetting.java12
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java40
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java19
-rw-r--r--services/core/java/com/android/server/display/PersistentDataStore.java89
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodBindingController.java4
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java22
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java1
-rw-r--r--services/core/java/com/android/server/logcat/LogAccessDialogActivity.java2
-rw-r--r--services/core/java/com/android/server/notification/toast/TextToastRecord.java3
-rw-r--r--services/core/java/com/android/server/pm/AppsFilterBase.java3
-rw-r--r--services/core/java/com/android/server/pm/FileInstallArgs.java19
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java5
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java5
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java58
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java37
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java4
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java10
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java4
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java5
-rw-r--r--services/core/java/com/android/server/testharness/OWNERS1
-rw-r--r--services/core/java/com/android/server/testharness/TestHarnessModeService.java6
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java47
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecordInputSink.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartController.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java125
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java12
-rw-r--r--services/core/java/com/android/server/wm/AnrController.java2
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java74
-rw-r--r--services/core/java/com/android/server/wm/AsyncRotationController.java8
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java11
-rw-r--r--services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java10
-rw-r--r--services/core/java/com/android/server/wm/DragState.java16
-rw-r--r--services/core/java/com/android/server/wm/InputConsumerImpl.java5
-rw-r--r--services/core/java/com/android/server/wm/Letterbox.java5
-rw-r--r--services/core/java/com/android/server/wm/LetterboxConfiguration.java78
-rw-r--r--services/core/java/com/android/server/wm/LetterboxUiController.java32
-rw-r--r--services/core/java/com/android/server/wm/NavBarFadeAnimationController.java4
-rw-r--r--services/core/java/com/android/server/wm/PinnedTaskController.java2
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java19
-rw-r--r--services/core/java/com/android/server/wm/SafeActivityOptions.java2
-rw-r--r--services/core/java/com/android/server/wm/StartingSurfaceController.java9
-rw-r--r--services/core/java/com/android/server/wm/SurfaceAnimator.java8
-rw-r--r--services/core/java/com/android/server/wm/Task.java3
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java68
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioner.java5
-rw-r--r--services/core/java/com/android/server/wm/Transition.java76
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java17
-rw-r--r--services/core/java/com/android/server/wm/TransitionTracer.java234
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java23
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowContainerThumbnail.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java31
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerShellCommand.java115
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java163
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java85
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java73
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java63
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java47
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java25
-rw-r--r--services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java13
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java40
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java16
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java37
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java15
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java25
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java157
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java216
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TransitionTests.java17
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java82
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java18
-rw-r--r--services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java124
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java1
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java38
-rw-r--r--telephony/java/android/telephony/UiccCardInfo.java3
-rw-r--r--telephony/java/android/telephony/UiccSlotInfo.java6
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt26
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml1
649 files changed, 11306 insertions, 3456 deletions
diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
index 88acf6507333..c43c832992cf 100644
--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
@@ -281,6 +281,20 @@ public interface AppStandbyInternal {
boolean shouldNoteResponseEventForAllBroadcastSessions();
/**
+ * Returns the list of roles whose holders are exempted from the requirement of starting
+ * a response event after receiving a broadcast.
+ */
+ @NonNull
+ List<String> getBroadcastResponseExemptedRoles();
+
+ /**
+ * Returns the list of permissions whose holders are exempted from the requirement of starting
+ * a response event after receiving a broadcast.
+ */
+ @NonNull
+ List<String> getBroadcastResponseExemptedPermissions();
+
+ /**
* Return the last known value corresponding to the {@code key} from
* {@link android.provider.DeviceConfig#NAMESPACE_APP_STANDBY} in AppStandbyController.
*/
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index c1f31e971ec5..9e3e3553c125 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -100,6 +100,7 @@ import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.Settings.Global;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
@@ -421,6 +422,26 @@ public class AppStandbyController
ConstantsObserver.DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS;
/**
+ * List of roles whose holders are exempted from the requirement of starting
+ * a response event after receiving a broadcast.
+ *
+ * The list of roles will be separated by '|' in the string.
+ */
+ volatile String mBroadcastResponseExemptedRoles =
+ ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_EXEMPTED_ROLES;
+ volatile List<String> mBroadcastResponseExemptedRolesList = Collections.EMPTY_LIST;
+
+ /**
+ * List of permissions whose holders are exempted from the requirement of starting
+ * a response event after receiving a broadcast.
+ *
+ * The list of permissions will be separated by '|' in the string.
+ */
+ volatile String mBroadcastResponseExemptedPermissions =
+ ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS;
+ volatile List<String> mBroadcastResponseExemptedPermissionsList = Collections.EMPTY_LIST;
+
+ /**
* Map of last known values of keys in {@link DeviceConfig#NAMESPACE_APP_STANDBY}.
*
* Note: We are intentionally not guarding this by any lock since this is only updated on
@@ -1960,6 +1981,18 @@ public class AppStandbyController
}
@Override
+ @NonNull
+ public List<String> getBroadcastResponseExemptedRoles() {
+ return mBroadcastResponseExemptedRolesList;
+ }
+
+ @Override
+ @NonNull
+ public List<String> getBroadcastResponseExemptedPermissions() {
+ return mBroadcastResponseExemptedPermissionsList;
+ }
+
+ @Override
@Nullable
public String getAppStandbyConstant(@NonNull String key) {
return mAppStandbyProperties.get(key);
@@ -2311,6 +2344,14 @@ public class AppStandbyController
pw.print(mNoteResponseEventForAllBroadcastSessions);
pw.println();
+ pw.print(" mBroadcastResponseExemptedRoles");
+ pw.print(mBroadcastResponseExemptedRoles);
+ pw.println();
+
+ pw.print(" mBroadcastResponseExemptedPermissions");
+ pw.print(mBroadcastResponseExemptedPermissions);
+ pw.println();
+
pw.println();
pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
pw.print(" mAllowRestrictedBucket=");
@@ -2795,6 +2836,10 @@ public class AppStandbyController
"broadcast_sessions_with_response_duration_ms";
private static final String KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS =
"note_response_event_for_all_broadcast_sessions";
+ private static final String KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES =
+ "brodacast_response_exempted_roles";
+ private static final String KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS =
+ "brodacast_response_exempted_permissions";
public static final long DEFAULT_CHECK_IDLE_INTERVAL_MS =
COMPRESS_TIME ? ONE_MINUTE : 4 * ONE_HOUR;
@@ -2837,6 +2882,11 @@ public class AppStandbyController
2 * ONE_MINUTE;
public static final boolean DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS =
true;
+ private static final String DEFAULT_BROADCAST_RESPONSE_EXEMPTED_ROLES = "";
+ private static final String DEFAULT_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS = "";
+
+ private final TextUtils.SimpleStringSplitter mStringPipeSplitter =
+ new TextUtils.SimpleStringSplitter('|');
ConstantsObserver(Handler handler) {
super(handler);
@@ -2989,6 +3039,20 @@ public class AppStandbyController
KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS,
DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS);
break;
+ case KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES:
+ mBroadcastResponseExemptedRoles = properties.getString(
+ KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES,
+ DEFAULT_BROADCAST_RESPONSE_EXEMPTED_ROLES);
+ mBroadcastResponseExemptedRolesList = splitPipeSeparatedString(
+ mBroadcastResponseExemptedRoles);
+ break;
+ case KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS:
+ mBroadcastResponseExemptedPermissions = properties.getString(
+ KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS,
+ DEFAULT_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS);
+ mBroadcastResponseExemptedPermissionsList = splitPipeSeparatedString(
+ mBroadcastResponseExemptedPermissions);
+ break;
default:
if (!timeThresholdsUpdated
&& (name.startsWith(KEY_PREFIX_SCREEN_TIME_THRESHOLD)
@@ -3003,6 +3067,15 @@ public class AppStandbyController
}
}
+ private List<String> splitPipeSeparatedString(String string) {
+ final List<String> values = new ArrayList<>();
+ mStringPipeSplitter.setString(string);
+ while (mStringPipeSplitter.hasNext()) {
+ values.add(mStringPipeSplitter.next());
+ }
+ return values;
+ }
+
private void updateTimeThresholds() {
// Query the values as an atomic set.
final DeviceConfig.Properties screenThresholdProperties =
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index e56ed39ea32e..581367a75804 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -733,7 +733,7 @@ status_t TombstoneSection::BlockingCall(unique_fd& pipeWriteFd) const {
return -errno;
}
- const std::set<int> hal_pids = get_interesting_hal_pids();
+ const std::set<int> hal_pids = get_interesting_pids();
auto pooledBuffer = get_buffer_from_pool();
ProtoOutputStream proto(pooledBuffer);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ae16e01b7788..7141259d7dce 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -8260,6 +8260,11 @@ public class Activity extends ContextThemeWrapper
return mMainThread;
}
+ /** @hide */
+ public final ActivityInfo getActivityInfo() {
+ return mActivityInfo;
+ }
+
final void performCreate(Bundle icicle) {
performCreate(icicle, null);
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 11d42461b4da..9e9e985d27de 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -298,6 +298,11 @@ public final class ActivityThread extends ClientTransactionHandler
/** Use background GC policy and default JIT threshold. */
private static final int VM_PROCESS_STATE_JANK_IMPERCEPTIBLE = 1;
+ /** The delay time for retrying to request DirectActions. */
+ private static final long REQUEST_DIRECT_ACTIONS_RETRY_TIME_MS = 200;
+ /** The max count for retrying to request DirectActions. */
+ private static final int REQUEST_DIRECT_ACTIONS_RETRY_MAX_COUNT = 7;
+
/**
* Denotes an invalid sequence number corresponding to a process state change.
*/
@@ -1864,7 +1869,8 @@ public final class ActivityThread extends ClientTransactionHandler
cancellationCallback.sendResult(cancellationResult);
}
mH.sendMessage(PooledLambda.obtainMessage(ActivityThread::handleRequestDirectActions,
- ActivityThread.this, activityToken, interactor, cancellationSignal, callback));
+ ActivityThread.this, activityToken, interactor, cancellationSignal, callback,
+ REQUEST_DIRECT_ACTIONS_RETRY_MAX_COUNT));
}
@Override
@@ -3940,7 +3946,7 @@ public final class ActivityThread extends ClientTransactionHandler
/** Fetches the user actions for the corresponding activity */
private void handleRequestDirectActions(@NonNull IBinder activityToken,
@NonNull IVoiceInteractor interactor, @NonNull CancellationSignal cancellationSignal,
- @NonNull RemoteCallback callback) {
+ @NonNull RemoteCallback callback, int retryCount) {
final ActivityClientRecord r = mActivities.get(activityToken);
if (r == null) {
Log.w(TAG, "requestDirectActions(): no activity for " + activityToken);
@@ -3948,7 +3954,20 @@ public final class ActivityThread extends ClientTransactionHandler
return;
}
final int lifecycleState = r.getLifecycleState();
- if (lifecycleState < ON_START || lifecycleState >= ON_STOP) {
+ if (lifecycleState < ON_START) {
+ // TODO(b/234173463): requestDirectActions callback should indicate errors
+ if (retryCount > 0) {
+ mH.sendMessageDelayed(
+ PooledLambda.obtainMessage(ActivityThread::handleRequestDirectActions,
+ ActivityThread.this, activityToken, interactor, cancellationSignal,
+ callback, retryCount - 1), REQUEST_DIRECT_ACTIONS_RETRY_TIME_MS);
+ return;
+ }
+ Log.w(TAG, "requestDirectActions(" + r + "): wrong lifecycle: " + lifecycleState);
+ callback.sendResult(null);
+ return;
+ }
+ if (lifecycleState >= ON_STOP) {
Log.w(TAG, "requestDirectActions(" + r + "): wrong lifecycle: " + lifecycleState);
callback.sendResult(null);
return;
diff --git a/core/java/android/app/ComponentOptions.java b/core/java/android/app/ComponentOptions.java
index 58732f015318..4e5e384a2798 100644
--- a/core/java/android/app/ComponentOptions.java
+++ b/core/java/android/app/ComponentOptions.java
@@ -99,8 +99,10 @@ public class ComponentOptions {
public Bundle toBundle() {
Bundle b = new Bundle();
b.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, mPendingIntentBalAllowed);
- b.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION,
- mPendingIntentBalAllowedByPermission);
+ if (mPendingIntentBalAllowedByPermission) {
+ b.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION,
+ mPendingIntentBalAllowedByPermission);
+ }
return b;
}
}
diff --git a/core/java/android/companion/virtual/IVirtualDeviceManager.aidl b/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
index a1640ee6d2e8..5418f7e93dd9 100644
--- a/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
+++ b/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
@@ -19,6 +19,8 @@ package android.companion.virtual;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.IVirtualDeviceActivityListener;
import android.companion.virtual.VirtualDeviceParams;
+import android.hardware.display.IVirtualDisplayCallback;
+import android.hardware.display.VirtualDisplayConfig;
/**
* Interface for communication between VirtualDeviceManager and VirtualDeviceManagerService.
@@ -42,4 +44,16 @@ interface IVirtualDeviceManager {
IVirtualDevice createVirtualDevice(
in IBinder token, String packageName, int associationId,
in VirtualDeviceParams params, in IVirtualDeviceActivityListener activityListener);
+
+ /**
+ * Creates a virtual display owned by a particular virtual device.
+ *
+ * @param virtualDisplayConfig The configuration used in creating the display
+ * @param callback A callback that receives display lifecycle events
+ * @param virtualDevice The device that will own this display
+ * @param packageName The package name of the calling app
+ */
+ int createVirtualDisplay(in VirtualDisplayConfig virtualDisplayConfig,
+ in IVirtualDisplayCallback callback, in IVirtualDevice virtualDevice,
+ String packageName);
}
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 3bb837317ad4..1b93bb851567 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -33,6 +33,8 @@ import android.content.Context;
import android.graphics.Point;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.VirtualDisplayFlag;
+import android.hardware.display.DisplayManagerGlobal;
+import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplay;
import android.hardware.display.VirtualDisplayConfig;
import android.hardware.input.VirtualKeyboard;
@@ -65,7 +67,7 @@ import java.util.function.IntConsumer;
public final class VirtualDeviceManager {
private static final boolean DEBUG = false;
- private static final String LOG_TAG = "VirtualDeviceManager";
+ private static final String TAG = "VirtualDeviceManager";
private static final int DEFAULT_VIRTUAL_DISPLAY_FLAGS =
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
@@ -150,6 +152,7 @@ public final class VirtualDeviceManager {
public static class VirtualDevice implements AutoCloseable {
private final Context mContext;
+ private final IVirtualDeviceManager mService;
private final IVirtualDevice mVirtualDevice;
private final ArrayMap<ActivityListener, ActivityListenerDelegate> mActivityListeners =
new ArrayMap<>();
@@ -189,6 +192,7 @@ public final class VirtualDeviceManager {
Context context,
int associationId,
VirtualDeviceParams params) throws RemoteException {
+ mService = service;
mContext = context.getApplicationContext();
mVirtualDevice = service.createVirtualDevice(
new Binder(),
@@ -274,18 +278,23 @@ public final class VirtualDeviceManager {
// TODO(b/205343547): Handle display groups properly instead of creating a new display
// group for every new virtual display created using this API.
// belongs to the same display group.
- DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
- // DisplayManager will call into VirtualDeviceManagerInternal to register the
- // created displays.
- return displayManager.createVirtualDisplay(
- mVirtualDevice,
- new VirtualDisplayConfig.Builder(
- getVirtualDisplayName(), width, height, densityDpi)
- .setSurface(surface)
- .setFlags(getVirtualDisplayFlags(flags))
- .build(),
- callback,
- executor);
+ VirtualDisplayConfig config = new VirtualDisplayConfig.Builder(
+ getVirtualDisplayName(), width, height, densityDpi)
+ .setSurface(surface)
+ .setFlags(getVirtualDisplayFlags(flags))
+ .build();
+ IVirtualDisplayCallback callbackWrapper =
+ new DisplayManagerGlobal.VirtualDisplayCallback(callback, executor);
+ final int displayId;
+ try {
+ displayId = mService.createVirtualDisplay(config, callbackWrapper, mVirtualDevice,
+ mContext.getPackageName());
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ DisplayManagerGlobal displayManager = DisplayManagerGlobal.getInstance();
+ return displayManager.createVirtualDisplayWrapper(config, mContext, callbackWrapper,
+ displayId);
}
/**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 836bff598ede..fce23cf6819a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3670,7 +3670,7 @@ public abstract class Context {
* <li>caller has {@code android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}</li>
* <li>caller has {@code android.Manifest.permission.INTERACT_ACROSS_USERS} and is the same
* package as the {@code service} (determined by its component's package) and the Android
- * version is at least {@link android.os.Build.VERSION_CODES#S}</li>
+ * version is at least {@link android.os.Build.VERSION_CODES#TIRAMISU}</li>
* <li>caller has {@code android.Manifest.permission.INTERACT_ACROSS_USERS} and is in same
* profile group as the given {@code user}</li>
* <li>caller has {@code android.Manifest.permission.INTERACT_ACROSS_PROFILES} and is in same
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 0673b3ad5b0a..a3d595ef6575 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -106,6 +106,24 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
public @interface LaunchMode {
}
+ /** @hide */
+ public static String launchModeToString(@LaunchMode int launchMode) {
+ switch(launchMode) {
+ case LAUNCH_MULTIPLE:
+ return "LAUNCH_MULTIPLE";
+ case LAUNCH_SINGLE_TOP:
+ return "LAUNCH_SINGLE_TOP";
+ case LAUNCH_SINGLE_TASK:
+ return "LAUNCH_SINGLE_TASK";
+ case LAUNCH_SINGLE_INSTANCE:
+ return "LAUNCH_SINGLE_INSTANCE";
+ case LAUNCH_SINGLE_INSTANCE_PER_TASK:
+ return "LAUNCH_SINGLE_INSTANCE_PER_TASK";
+ default:
+ return "unknown=" + launchMode;
+ }
+ }
+
/**
* The launch mode style requested by the activity. From the
* {@link android.R.attr#launchMode} attribute.
@@ -1585,7 +1603,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
+ " persistableMode=" + persistableModeToString());
}
if (launchMode != 0 || flags != 0 || privateFlags != 0 || theme != 0) {
- pw.println(prefix + "launchMode=" + launchMode
+ pw.println(prefix + "launchMode=" + launchModeToString(launchMode)
+ " flags=0x" + Integer.toHexString(flags)
+ " privateFlags=0x" + Integer.toHexString(privateFlags)
+ " theme=0x" + Integer.toHexString(theme));
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index eadcac91dcd7..b505395a091a 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -31,7 +31,6 @@ import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.app.KeyguardManager;
-import android.companion.virtual.IVirtualDevice;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Resources;
@@ -971,17 +970,8 @@ public final class DisplayManager {
executor = new HandlerExecutor(
Handler.createAsync(handler != null ? handler.getLooper() : Looper.myLooper()));
}
- return mGlobal.createVirtualDisplay(mContext, projection, null /* virtualDevice */,
- virtualDisplayConfig, callback, executor, windowContext);
- }
-
- /** @hide */
- public VirtualDisplay createVirtualDisplay(@Nullable IVirtualDevice virtualDevice,
- @NonNull VirtualDisplayConfig virtualDisplayConfig,
- @Nullable VirtualDisplay.Callback callback,
- @Nullable Executor executor) {
- return mGlobal.createVirtualDisplay(mContext, null /* projection */, virtualDevice,
- virtualDisplayConfig, callback, executor, null);
+ return mGlobal.createVirtualDisplay(mContext, projection, virtualDisplayConfig, callback,
+ executor, windowContext);
}
/**
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index a62bbf623000..74356ddecc76 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -24,7 +24,6 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PropertyInvalidatedCache;
-import android.companion.virtual.IVirtualDevice;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.ParceledListSlice;
@@ -586,18 +585,28 @@ public final class DisplayManagerGlobal {
}
public VirtualDisplay createVirtualDisplay(@NonNull Context context, MediaProjection projection,
- IVirtualDevice virtualDevice, @NonNull VirtualDisplayConfig virtualDisplayConfig,
- VirtualDisplay.Callback callback, @Nullable Executor executor,
- @Nullable Context windowContext) {
+ @NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback,
+ @Nullable Executor executor, @Nullable Context windowContext) {
VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, executor);
IMediaProjection projectionToken = projection != null ? projection.getProjection() : null;
int displayId;
try {
displayId = mDm.createVirtualDisplay(virtualDisplayConfig, callbackWrapper,
- projectionToken, virtualDevice, context.getPackageName());
+ projectionToken, context.getPackageName());
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
+ return createVirtualDisplayWrapper(virtualDisplayConfig, windowContext, callbackWrapper,
+ displayId);
+ }
+
+ /**
+ * Create a VirtualDisplay wrapper object for a newly created virtual display ; to be called
+ * once the display has been created in system_server.
+ */
+ @Nullable
+ public VirtualDisplay createVirtualDisplayWrapper(VirtualDisplayConfig virtualDisplayConfig,
+ Context windowContext, IVirtualDisplayCallback callbackWrapper, int displayId) {
if (displayId < 0) {
Log.e(TAG, "Could not create virtual display: " + virtualDisplayConfig.getName());
return null;
@@ -1050,7 +1059,10 @@ public final class DisplayManagerGlobal {
}
}
- private final static class VirtualDisplayCallback extends IVirtualDisplayCallback.Stub {
+ /**
+ * Assists in dispatching VirtualDisplay lifecycle event callbacks on a given Executor.
+ */
+ public static final class VirtualDisplayCallback extends IVirtualDisplayCallback.Stub {
@Nullable private final VirtualDisplay.Callback mCallback;
@Nullable private final Executor mExecutor;
@@ -1062,7 +1074,7 @@ public final class DisplayManagerGlobal {
* @param executor The executor to call the {@code callback} on. Must not be {@code null} if
* the callback is not {@code null}.
*/
- VirtualDisplayCallback(VirtualDisplay.Callback callback, Executor executor) {
+ public VirtualDisplayCallback(VirtualDisplay.Callback callback, Executor executor) {
mCallback = callback;
mExecutor = mCallback != null ? Objects.requireNonNull(executor) : null;
}
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index be482c9146c9..1c3bec5b52f4 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -18,6 +18,7 @@ package android.hardware.display;
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.companion.virtual.IVirtualDevice;
import android.graphics.Point;
import android.hardware.SensorManager;
import android.os.Handler;
@@ -60,6 +61,14 @@ public abstract class DisplayManagerInternal {
Handler handler, SensorManager sensorManager);
/**
+ * Called by the VirtualDeviceManagerService to create a VirtualDisplay owned by a
+ * VirtualDevice.
+ */
+ public abstract int createVirtualDisplay(VirtualDisplayConfig config,
+ IVirtualDisplayCallback callback, IVirtualDevice virtualDevice,
+ DisplayWindowPolicyController dwpc, String packageName);
+
+ /**
* Called by the power manager to request a new power state.
* <p>
* The display power controller makes a copy of the provided object and then
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index ddd18f4502e7..ca3e58094400 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -16,7 +16,6 @@
package android.hardware.display;
-import android.companion.virtual.IVirtualDevice;
import android.content.pm.ParceledListSlice;
import android.graphics.Point;
import android.hardware.display.BrightnessConfiguration;
@@ -88,10 +87,10 @@ interface IDisplayManager {
void requestColorMode(int displayId, int colorMode);
// Requires CAPTURE_VIDEO_OUTPUT, CAPTURE_SECURE_VIDEO_OUTPUT, or an appropriate
- // MediaProjection token or VirtualDevice for certain combinations of flags.
+ // MediaProjection token for certain combinations of flags.
int createVirtualDisplay(in VirtualDisplayConfig virtualDisplayConfig,
in IVirtualDisplayCallback callback, in IMediaProjection projectionToken,
- in IVirtualDevice virtualDevice, String packageName);
+ String packageName);
// No permissions required, but must be same Uid as the creator.
void resizeVirtualDisplay(in IVirtualDisplayCallback token,
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 21ecf8b0888c..334a659d7f23 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -806,11 +806,6 @@ public class InputMethodService extends AbstractInputMethodService {
@NonNull EditorInfo editorInfo, boolean restarting,
@NonNull IBinder startInputToken, @InputMethodNavButtonFlags int navButtonFlags,
@NonNull ImeOnBackInvokedDispatcher imeDispatcher) {
- mImeDispatcher = imeDispatcher;
- if (mWindow != null) {
- mWindow.getOnBackInvokedDispatcher().setImeOnBackInvokedDispatcher(
- imeDispatcher);
- }
mPrivOps.reportStartInputAsync(startInputToken);
mNavigationBarController.onNavButtonFlagsChanged(navButtonFlags);
if (restarting) {
@@ -818,6 +813,15 @@ public class InputMethodService extends AbstractInputMethodService {
} else {
startInput(inputConnection, editorInfo);
}
+ // Update the IME dispatcher last, so that the previously registered back callback
+ // (if any) can be unregistered using the old dispatcher if {@link #doFinishInput()}
+ // is called from {@link #startInput(InputConnection, EditorInfo)} or
+ // {@link #restartInput(InputConnection, EditorInfo)}.
+ mImeDispatcher = imeDispatcher;
+ if (mWindow != null) {
+ mWindow.getOnBackInvokedDispatcher().setImeOnBackInvokedDispatcher(
+ imeDispatcher);
+ }
}
/**
@@ -3860,6 +3864,11 @@ public class InputMethodService extends AbstractInputMethodService {
};
private void compatHandleBack() {
+ if (!mDecorViewVisible) {
+ Log.e(TAG, "Back callback invoked on a hidden IME. Removing the callback...");
+ unregisterCompatOnBackInvokedCallback();
+ return;
+ }
final KeyEvent downEvent = createBackKeyEvent(
KeyEvent.ACTION_DOWN, false /* isTracking */);
onKeyDown(KeyEvent.KEYCODE_BACK, downEvent);
diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java
index f62d7c4a698d..2e64a74a5d67 100644
--- a/core/java/android/net/VpnManager.java
+++ b/core/java/android/net/VpnManager.java
@@ -100,6 +100,12 @@ public class VpnManager {
/**
* Action sent in {@link android.content.Intent}s to VpnManager clients when an event occurred.
*
+ * <p>If the provisioning application declares a service handling this intent action, but is not
+ * already running, it will be started. Upon starting, the application is granted a short grace
+ * period to run in the background even while the device is idle to handle any potential
+ * failures. Applications requiring long-running actions triggered by one of these events should
+ * declare a foreground service to prevent being killed once the grace period expires.
+ *
* This action will have a category of either {@link #CATEGORY_EVENT_IKE_ERROR},
* {@link #CATEGORY_EVENT_NETWORK_ERROR}, or {@link #CATEGORY_EVENT_DEACTIVATED_BY_USER},
* that the app can use to filter events it's interested in reacting to.
diff --git a/core/java/android/nfc/INfcTag.aidl b/core/java/android/nfc/INfcTag.aidl
index e1ccc4fb740b..170df71385bb 100644
--- a/core/java/android/nfc/INfcTag.aidl
+++ b/core/java/android/nfc/INfcTag.aidl
@@ -46,6 +46,5 @@ interface INfcTag
int getMaxTransceiveLength(int technology);
boolean getExtendedLengthApdusSupported();
- void setTagUpToDate(long cookie);
boolean isTagUpToDate(long cookie);
}
diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java
index 731d1ba78299..500038f14d9d 100644
--- a/core/java/android/nfc/Tag.java
+++ b/core/java/android/nfc/Tag.java
@@ -34,7 +34,6 @@ import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
-import android.os.SystemClock;
import java.io.IOException;
import java.util.Arrays;
@@ -119,17 +118,17 @@ public final class Tag implements Parcelable {
final String[] mTechStringList;
final Bundle[] mTechExtras;
final int mServiceHandle; // for use by NFC service, 0 indicates a mock
+ final long mCookie; // for accessibility checking
final INfcTag mTagService; // interface to NFC service, will be null if mock tag
int mConnectedTechnology;
- long mCookie;
/**
* Hidden constructor to be used by NFC service and internal classes.
* @hide
*/
public Tag(byte[] id, int[] techList, Bundle[] techListExtras, int serviceHandle,
- INfcTag tagService) {
+ long cookie, INfcTag tagService) {
if (techList == null) {
throw new IllegalArgumentException("rawTargets cannot be null");
}
@@ -139,20 +138,13 @@ public final class Tag implements Parcelable {
// Ensure mTechExtras is as long as mTechList
mTechExtras = Arrays.copyOf(techListExtras, techList.length);
mServiceHandle = serviceHandle;
+ mCookie = cookie;
mTagService = tagService;
-
mConnectedTechnology = -1;
- mCookie = SystemClock.elapsedRealtime();
if (tagService == null) {
return;
}
-
- try {
- tagService.setTagUpToDate(mCookie);
- } catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
- }
}
/**
@@ -165,9 +157,10 @@ public final class Tag implements Parcelable {
* @return freshly constructed tag
* @hide
*/
- public static Tag createMockTag(byte[] id, int[] techList, Bundle[] techListExtras) {
+ public static Tag createMockTag(byte[] id, int[] techList, Bundle[] techListExtras,
+ long cookie) {
// set serviceHandle to 0 and tagService to null to indicate mock tag
- return new Tag(id, techList, techListExtras, 0, null);
+ return new Tag(id, techList, techListExtras, 0, cookie, null);
}
private String[] generateTechStringList(int[] techList) {
@@ -445,6 +438,7 @@ public final class Tag implements Parcelable {
dest.writeIntArray(mTechList);
dest.writeTypedArray(mTechExtras, 0);
dest.writeInt(mServiceHandle);
+ dest.writeLong(mCookie);
dest.writeInt(isMock);
if (isMock == 0) {
dest.writeStrongBinder(mTagService.asBinder());
@@ -463,6 +457,7 @@ public final class Tag implements Parcelable {
in.readIntArray(techList);
Bundle[] techExtras = in.createTypedArray(Bundle.CREATOR);
int serviceHandle = in.readInt();
+ long cookie = in.readLong();
int isMock = in.readInt();
if (isMock == 0) {
tagService = INfcTag.Stub.asInterface(in.readStrongBinder());
@@ -471,7 +466,7 @@ public final class Tag implements Parcelable {
tagService = null;
}
- return new Tag(id, techList, techExtras, serviceHandle, tagService);
+ return new Tag(id, techList, techExtras, serviceHandle, cookie, tagService);
}
@Override
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d1ff9f79d96a..7964f7cd6908 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10871,6 +10871,15 @@ public final class Settings {
"launcher_taskbar_education_showing";
/**
+ * Whether or not adaptive charging feature is enabled by user.
+ * Type: int (0 for false, 1 for true)
+ * Default: 1
+ *
+ * @hide
+ */
+ public static final String ADAPTIVE_CHARGING_ENABLED = "adaptive_charging_enabled";
+
+ /**
* These entries are considered common between the personal and the managed profile,
* since the managed profile doesn't get to change them.
*/
@@ -11433,7 +11442,7 @@ public final class Settings {
* Whether or not data roaming is enabled. (0 = false, 1 = true)
* Use {@link TelephonyManager#isDataRoamingEnabled} instead of calling via settings.
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.S)
+ @Readable(maxTargetSdk = Build.VERSION_CODES.S_V2)
public static final String DATA_ROAMING = "data_roaming";
/**
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 5217b28942f8..2d461c6cf92e 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -1130,18 +1130,16 @@ public class DreamService extends Service implements Window.Callback {
final PackageManager pm = context.getPackageManager();
- final TypedArray rawMetadata = readMetadata(pm, serviceInfo);
- if (rawMetadata == null) return null;
-
- final DreamMetadata metadata = new DreamMetadata(
- convertToComponentName(rawMetadata.getString(
- com.android.internal.R.styleable.Dream_settingsActivity), serviceInfo),
- rawMetadata.getDrawable(
- com.android.internal.R.styleable.Dream_previewImage),
- rawMetadata.getBoolean(R.styleable.Dream_showClockAndComplications,
- DEFAULT_SHOW_COMPLICATIONS));
- rawMetadata.recycle();
- return metadata;
+ try (TypedArray rawMetadata = readMetadata(pm, serviceInfo)) {
+ if (rawMetadata == null) return null;
+ return new DreamMetadata(
+ convertToComponentName(rawMetadata.getString(
+ com.android.internal.R.styleable.Dream_settingsActivity), serviceInfo),
+ rawMetadata.getDrawable(
+ com.android.internal.R.styleable.Dream_previewImage),
+ rawMetadata.getBoolean(R.styleable.Dream_showClockAndComplications,
+ DEFAULT_SHOW_COMPLICATIONS));
+ }
}
/**
diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
index 3cffeb0578d4..380c1045aea8 100644
--- a/core/java/android/view/FrameMetrics.java
+++ b/core/java/android/view/FrameMetrics.java
@@ -254,8 +254,9 @@ public final class FrameMetrics {
int GPU_COMPLETED = 19;
int SWAP_BUFFERS_COMPLETED = 20;
int DISPLAY_PRESENT_TIME = 21;
+ int COMMAND_SUBMISSION_COMPLETED = 22;
- int FRAME_STATS_COUNT = 22; // must always be last and in sync with
+ int FRAME_STATS_COUNT = 23; // must always be last and in sync with
// FrameInfoIndex::NumIndexes in libs/hwui/FrameInfo.h
}
@@ -291,7 +292,7 @@ public final class FrameMetrics {
// RESERVED VSYNC_TIMESTAMP
0, 0,
// GPU_DURATION
- Index.SWAP_BUFFERS, Index.GPU_COMPLETED,
+ Index.COMMAND_SUBMISSION_COMPLETED, Index.GPU_COMPLETED,
// DEADLINE
Index.INTENDED_VSYNC, Index.FRAME_DEADLINE,
};
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index f246cd9fa107..acdff4fb52fd 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -543,6 +543,21 @@ interface IWindowManager
boolean isWindowTraceEnabled();
/**
+ * Starts a transition trace.
+ */
+ void startTransitionTrace();
+
+ /**
+ * Stops a transition trace.
+ */
+ void stopTransitionTrace();
+
+ /**
+ * Returns true if transition trace is enabled.
+ */
+ boolean isTransitionTraceEnabled();
+
+ /**
* Gets the windowing mode of the display.
*
* @param displayId The id of the display.
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index 0b05d94663cc..2922ad6ff6a8 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -210,6 +210,7 @@ public final class InputWindowHandle {
.append(", scaleFactor=").append(scaleFactor)
.append(", transform=").append(transform)
.append(", windowToken=").append(windowToken)
+ .append(", isClone=").append(isClone)
.toString();
}
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index d6b75b94b19a..b17e19998a9d 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -36,6 +36,7 @@ import android.annotation.IntDef;
import android.annotation.Nullable;
import android.graphics.Insets;
import android.graphics.Rect;
+import android.util.ArraySet;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.InsetsState.InternalInsetsType;
@@ -272,11 +273,7 @@ public class InsetsSourceConsumer {
mController.getHost().getInputMethodManager(), null /* icProto */);
}
- // We still need to let the legacy app know the visibility change even if we don't have the
- // control. If we don't have the source, we don't change the requested visibility for making
- // the callback behavior compatible.
- mController.updateCompatSysUiVisibility(
- mType, (hasControl || source == null) ? mRequestedVisible : isVisible, hasControl);
+ updateCompatSysUiVisibility(hasControl, source, isVisible);
// If we don't have control, we are not able to change the visibility.
if (!hasControl) {
@@ -294,6 +291,36 @@ public class InsetsSourceConsumer {
return true;
}
+ private void updateCompatSysUiVisibility(boolean hasControl, InsetsSource source,
+ boolean visible) {
+ final @InsetsType int publicType = InsetsState.toPublicType(mType);
+ if (publicType != WindowInsets.Type.statusBars()
+ && publicType != WindowInsets.Type.navigationBars()) {
+ // System UI visibility only controls status bars and navigation bars.
+ return;
+ }
+ final boolean compatVisible;
+ if (hasControl) {
+ compatVisible = mRequestedVisible;
+ } else if (source != null && !source.getFrame().isEmpty()) {
+ compatVisible = visible;
+ } else {
+ final ArraySet<Integer> types = InsetsState.toInternalType(publicType);
+ for (int i = types.size() - 1; i >= 0; i--) {
+ final InsetsSource s = mState.peekSource(types.valueAt(i));
+ if (s != null && !s.getFrame().isEmpty()) {
+ // The compat system UI visibility would be updated by another consumer which
+ // handles the same public insets type.
+ return;
+ }
+ }
+ // No one provides the public type. Use the requested visibility for making the callback
+ // behavior compatible.
+ compatVisible = mRequestedVisible;
+ }
+ mController.updateCompatSysUiVisibility(mType, compatVisible, hasControl);
+ }
+
@VisibleForTesting
public boolean isRequestedVisible() {
return mRequestedVisible;
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 2e48c2b77233..7e264cea46bb 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -719,13 +719,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
private void releaseSurfaces(boolean releaseSurfacePackage) {
mSurfaceAlpha = 1f;
-
- mSurfaceLock.lock();
- try {
- mSurface.destroy();
- } finally {
- mSurfaceLock.unlock();
- }
+ mSurface.destroy();
+
synchronized (mSurfaceControlLock) {
if (mBlastBufferQueue != null) {
mBlastBufferQueue.destroy();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 90497e7adbf7..ba6ba63e4ed0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10000,7 +10000,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// We reset any translation state as views may be re-used (e.g., as in ListView and
// RecyclerView). We only need to do this for views important for content capture since
// views unimportant for content capture won't be translated anyway.
- clearTranslationState();
+ if (!isTemporarilyDetached()) {
+ clearTranslationState();
+ }
}
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 7353bbccf77c..7d7270d1ef76 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -522,6 +522,61 @@ public final class AutofillManager {
public static final int RESULT_CODE_NOT_SERVICE = -1;
/**
+ * Reasons to commit the Autofill context.
+ *
+ * <p>If adding a new reason, modify
+ * {@link com.android.server.autofill.PresentationStatsEventLogger#getNoPresentationEventReason(int)}
+ * as well.</p>
+ *
+ * TODO(b/233833662): Expose this as a public API in U.
+ * @hide
+ */
+ @IntDef(prefix = { "COMMIT_REASON_" }, value = {
+ COMMIT_REASON_UNKNOWN,
+ COMMIT_REASON_ACTIVITY_FINISHED,
+ COMMIT_REASON_VIEW_COMMITTED,
+ COMMIT_REASON_VIEW_CLICKED,
+ COMMIT_REASON_VIEW_CHANGED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AutofillCommitReason {}
+
+ /**
+ * Autofill context was committed because of an unknown reason.
+ *
+ * @hide
+ */
+ public static final int COMMIT_REASON_UNKNOWN = 0;
+
+ /**
+ * Autofill context was committed because activity finished.
+ *
+ * @hide
+ */
+ public static final int COMMIT_REASON_ACTIVITY_FINISHED = 1;
+
+ /**
+ * Autofill context was committed because {@link #commit()} was called.
+ *
+ * @hide
+ */
+ public static final int COMMIT_REASON_VIEW_COMMITTED = 2;
+
+ /**
+ * Autofill context was committed because view was clicked.
+ *
+ * @hide
+ */
+ public static final int COMMIT_REASON_VIEW_CLICKED = 3;
+
+ /**
+ * Autofill context was committed because of view changed.
+ *
+ * @hide
+ */
+ public static final int COMMIT_REASON_VIEW_CHANGED = 4;
+
+ /**
* Makes an authentication id from a request id and a dataset id.
*
* @param requestId The request id.
@@ -1585,7 +1640,7 @@ public final class AutofillManager {
}
if (mSaveTriggerId != null && mSaveTriggerId.equals(id)) {
if (sDebug) Log.d(TAG, "triggering commit by click of " + id);
- commitLocked();
+ commitLocked(/* commitReason= */ COMMIT_REASON_VIEW_CLICKED);
mMetricsLogger.write(newLog(MetricsEvent.AUTOFILL_SAVE_EXPLICITLY_TRIGGERED));
}
}
@@ -1603,7 +1658,7 @@ public final class AutofillManager {
synchronized (mLock) {
if (mSaveOnFinish) {
if (sDebug) Log.d(TAG, "onActivityFinishing(): calling commitLocked()");
- commitLocked();
+ commitLocked(/* commitReason= */ COMMIT_REASON_ACTIVITY_FINISHED);
} else {
if (sDebug) Log.d(TAG, "onActivityFinishing(): calling cancelLocked()");
cancelLocked();
@@ -1628,16 +1683,16 @@ public final class AutofillManager {
}
if (sVerbose) Log.v(TAG, "commit() called by app");
synchronized (mLock) {
- commitLocked();
+ commitLocked(/* commitReason= */ COMMIT_REASON_VIEW_COMMITTED);
}
}
@GuardedBy("mLock")
- private void commitLocked() {
+ private void commitLocked(@AutofillCommitReason int commitReason) {
if (!mEnabled && !isActiveLocked()) {
return;
}
- finishSessionLocked();
+ finishSessionLocked(/* commitReason= */ commitReason);
}
/**
@@ -2070,13 +2125,13 @@ public final class AutofillManager {
}
@GuardedBy("mLock")
- private void finishSessionLocked() {
+ private void finishSessionLocked(@AutofillCommitReason int commitReason) {
if (sVerbose) Log.v(TAG, "finishSessionLocked(): " + getStateAsStringLocked());
if (!isActiveLocked()) return;
try {
- mService.finishSession(mSessionId, mContext.getUserId());
+ mService.finishSession(mSessionId, mContext.getUserId(), commitReason);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3549,7 +3604,7 @@ public final class AutofillManager {
}
if (mVisibleTrackedIds == null) {
- finishSessionLocked();
+ finishSessionLocked(/* commitReason= */ COMMIT_REASON_VIEW_CHANGED);
}
}
@@ -3582,9 +3637,9 @@ public final class AutofillManager {
if (mVisibleTrackedIds == null) {
if (sVerbose) {
- Log.v(TAG, "No more visible ids. Invisibile = " + mInvisibleTrackedIds);
+ Log.v(TAG, "No more visible ids. Invisible = " + mInvisibleTrackedIds);
}
- finishSessionLocked();
+ finishSessionLocked(/* commitReason= */ COMMIT_REASON_VIEW_CHANGED);
}
}
@@ -3656,7 +3711,7 @@ public final class AutofillManager {
if (sVerbose) {
Log.v(TAG, "onVisibleForAutofillChangedLocked(): no more visible ids");
}
- finishSessionLocked();
+ finishSessionLocked(/* commitReason= */ COMMIT_REASON_VIEW_CHANGED);
}
}
}
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index a507e74c30ab..cefd6dc13005 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -49,7 +49,7 @@ oneway interface IAutoFillManager {
void updateSession(int sessionId, in AutofillId id, in Rect bounds,
in AutofillValue value, int action, int flags, int userId);
void setAutofillFailure(int sessionId, in List<AutofillId> ids, int userId);
- void finishSession(int sessionId, int userId);
+ void finishSession(int sessionId, int userId, int commitReason);
void cancelSession(int sessionId, int userId);
void setAuthenticationResult(in Bundle data, int sessionId, int authenticationId, int userId);
void setHasCallback(int sessionId, int userId, boolean hasIt);
diff --git a/core/java/android/view/translation/ViewTranslationCallback.java b/core/java/android/view/translation/ViewTranslationCallback.java
index 3936b639592d..a95d95fe20a2 100644
--- a/core/java/android/view/translation/ViewTranslationCallback.java
+++ b/core/java/android/view/translation/ViewTranslationCallback.java
@@ -52,6 +52,15 @@ public interface ViewTranslationCallback {
* the original text instead of the translated text or use a different approach to display the
* translated text.
*
+ * <p> NOTE: In Android version {@link android.os.Build.VERSION_CODES#TIRAMISU} and later,
+ * the implementation must be able to handle a selectable {@link android.widget.TextView}
+ * (i.e., {@link android.widget.TextView#isTextSelectable()} returns {@code true}. The default
+ * callback implementation for TextView uses a {@link android.text.method.TransformationMethod}
+ * to show the translated text, which will cause a crash when the translated text is selected.
+ * Therefore, the default callback temporarily makes the TextView non-selectable while the
+ * translation text is shown. This is one approach for handling selectable TextViews a
+ * TransformationMethod is used.
+ *
* See {@link View#onViewTranslationResponse} for how to get the translated information.
*
* @return {@code true} if the View handles showing the translation.
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 93f72640bd3f..e745b8cf769b 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -14240,13 +14240,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* Collects a {@link ViewTranslationRequest} which represents the content to be translated in
* the view.
*
- * <p>NOTE: When overriding the method, it should not translate the password. If the subclass
- * uses {@link TransformationMethod} to display the translated result, it's also not recommend
- * to translate text is selectable or editable.
+ * <p>NOTE: When overriding the method, it should not collect a request to translate this
+ * TextView if it is displaying a password.
*
* @param supportedFormats the supported translation format. The value could be {@link
* android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}.
- * @return the {@link ViewTranslationRequest} which contains the information to be translated.
+ * @param requestsCollector {@link Consumer} to receiver the {@link ViewTranslationRequest}
+ * which contains the information to be translated.
*/
@Override
public void onCreateViewTranslationRequest(@NonNull int[] supportedFormats,
@@ -14268,18 +14268,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return;
}
boolean isPassword = isAnyPasswordInputType() || hasPasswordTransformationMethod();
- // TODO(b/177214256): support selectable text translation.
- // We use the TransformationMethod to implement showing the translated text. The
- // TextView does not support the text length change for TransformationMethod. If the
- // text is selectable or editable, it will crash while selecting the text. To support
- // it, it needs broader changes to text APIs, we only allow to translate non selectable
- // and editable text in S.
- if (isTextEditable() || isPassword || isTextSelectable()) {
- if (UiTranslationController.DEBUG) {
- Log.w(LOG_TAG, "Cannot create translation request. editable = "
- + isTextEditable() + ", isPassword = " + isPassword + ", selectable = "
- + isTextSelectable());
- }
+ if (isTextEditable() || isPassword) {
+ Log.w(LOG_TAG, "Cannot create translation request. editable = "
+ + isTextEditable() + ", isPassword = " + isPassword);
return;
}
// TODO(b/176488462): apply the view's important for translation
diff --git a/core/java/android/widget/TextViewTranslationCallback.java b/core/java/android/widget/TextViewTranslationCallback.java
index 1713d842560b..5ad45790dae8 100644
--- a/core/java/android/widget/TextViewTranslationCallback.java
+++ b/core/java/android/widget/TextViewTranslationCallback.java
@@ -32,6 +32,8 @@ import android.view.translation.ViewTranslationCallback;
import android.view.translation.ViewTranslationRequest;
import android.view.translation.ViewTranslationResponse;
+import java.lang.ref.WeakReference;
+
/**
* Default implementation for {@link ViewTranslationCallback} for {@link TextView} components.
* This class handles how to display the translated information for {@link TextView}.
@@ -48,6 +50,11 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
private boolean mIsShowingTranslation = false;
private boolean mAnimationRunning = false;
private boolean mIsTextPaddingEnabled = false;
+ private boolean mOriginalIsTextSelectable = false;
+ private int mOriginalFocusable = 0;
+ private boolean mOriginalFocusableInTouchMode = false;
+ private boolean mOriginalClickable = false;
+ private boolean mOriginalLongClickable = false;
private CharSequence mPaddedText;
private int mAnimationDurationMillis = 250; // default value
@@ -81,21 +88,50 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
// update the translation response to keep the result up to date.
// Because TextView.setTransformationMethod() will skip the same TransformationMethod
// instance, we should create a new one to let new translation can work.
+ TextView theTextView = (TextView) view;
if (mTranslationTransformation == null
|| !response.equals(mTranslationTransformation.getViewTranslationResponse())) {
TransformationMethod originalTranslationMethod =
- ((TextView) view).getTransformationMethod();
+ theTextView.getTransformationMethod();
mTranslationTransformation = new TranslationTransformationMethod(response,
originalTranslationMethod);
}
final TransformationMethod transformation = mTranslationTransformation;
+ WeakReference<TextView> textViewRef = new WeakReference<>(theTextView);
runChangeTextWithAnimationIfNeeded(
- (TextView) view,
+ theTextView,
() -> {
mIsShowingTranslation = true;
mAnimationRunning = false;
- // TODO(b/178353965): well-handle setTransformationMethod.
- ((TextView) view).setTransformationMethod(transformation);
+
+ TextView textView = textViewRef.get();
+ if (textView == null) {
+ return;
+ }
+ // TODO(b/177214256): support selectable text translation.
+ // We use the TransformationMethod to implement showing the translated text. The
+ // TextView does not support the text length change for TransformationMethod.
+ // If the text is selectable or editable, it will crash while selecting the
+ // text. To support being able to select translated text, we need broader
+ // changes to text APIs. For now, the callback makes the text non-selectable
+ // while translated, and makes it selectable again after translation.
+ mOriginalIsTextSelectable = textView.isTextSelectable();
+ if (mOriginalIsTextSelectable) {
+ // According to documentation for `setTextIsSelectable()`, it sets the
+ // flags focusable, focusableInTouchMode, clickable, and longClickable
+ // to the same value. We get the original values to restore when translation
+ // is hidden.
+ mOriginalFocusableInTouchMode = textView.isFocusableInTouchMode();
+ mOriginalFocusable = textView.getFocusable();
+ mOriginalClickable = textView.isClickable();
+ mOriginalLongClickable = textView.isLongClickable();
+ textView.setTextIsSelectable(false);
+ }
+
+ // TODO(b/233406028): We should NOT restore the original
+ // TransformationMethod and selectable state if it was changed WHILE
+ // translation was being shown.
+ textView.setTransformationMethod(transformation);
});
if (response.getKeys().contains(ViewTranslationRequest.ID_CONTENT_DESCRIPTION)) {
CharSequence translatedContentDescription =
@@ -122,12 +158,34 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
if (mTranslationTransformation != null) {
final TransformationMethod transformation =
mTranslationTransformation.getOriginalTransformationMethod();
+ TextView theTextView = (TextView) view;
+ WeakReference<TextView> textViewRef = new WeakReference<>(theTextView);
runChangeTextWithAnimationIfNeeded(
- (TextView) view,
+ theTextView,
() -> {
mIsShowingTranslation = false;
mAnimationRunning = false;
- ((TextView) view).setTransformationMethod(transformation);
+
+ TextView textView = textViewRef.get();
+ if (textView == null) {
+ return;
+ }
+ // TODO(b/233406028): We should NOT restore the original
+ // TransformationMethod and selectable state if it was changed WHILE
+ // translation was being shown.
+ textView.setTransformationMethod(transformation);
+
+ if (mOriginalIsTextSelectable && !textView.isTextSelectable()) {
+ // According to documentation for `setTextIsSelectable()`, it sets the
+ // flags focusable, focusableInTouchMode, clickable, and longClickable
+ // to the same value, and you must call `setFocusable()`, etc. to
+ // restore all previous flag values.
+ textView.setTextIsSelectable(true);
+ textView.setFocusableInTouchMode(mOriginalFocusableInTouchMode);
+ textView.setFocusable(mOriginalFocusable);
+ textView.setClickable(mOriginalClickable);
+ textView.setLongClickable(mOriginalLongClickable);
+ }
});
if (!TextUtils.isEmpty(mContentDescription)) {
view.setContentDescription(mContentDescription);
@@ -258,6 +316,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
mAnimator.setRepeatCount(1);
mAnimator.setDuration(mAnimationDurationMillis);
final ColorStateList originalColors = view.getTextColors();
+ WeakReference<TextView> viewRef = new WeakReference<>(view);
mAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
@@ -265,7 +324,10 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
@Override
public void onAnimationEnd(Animator animation) {
- view.setTextColor(originalColors);
+ TextView view = viewRef.get();
+ if (view != null) {
+ view.setTextColor(originalColors);
+ }
mAnimator = null;
}
diff --git a/core/java/android/window/DisplayWindowPolicyController.java b/core/java/android/window/DisplayWindowPolicyController.java
index d3cc918c2a29..a5aefd5157ce 100644
--- a/core/java/android/window/DisplayWindowPolicyController.java
+++ b/core/java/android/window/DisplayWindowPolicyController.java
@@ -126,6 +126,11 @@ public abstract class DisplayWindowPolicyController {
ActivityInfo activityInfo, int windowFlags, int systemWindowFlags);
/**
+ * Returns {@code true} if the tasks which is on this virtual display can be showed on Recents.
+ */
+ public abstract boolean canShowTasksInRecents();
+
+ /**
* This is called when the top activity of the display is changed.
*/
public void onTopActivityChanged(ComponentName topActivity, int uid) {}
diff --git a/core/java/android/window/ProxyOnBackInvokedDispatcher.java b/core/java/android/window/ProxyOnBackInvokedDispatcher.java
index bedf5038f669..10d43e89a09d 100644
--- a/core/java/android/window/ProxyOnBackInvokedDispatcher.java
+++ b/core/java/android/window/ProxyOnBackInvokedDispatcher.java
@@ -90,7 +90,11 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
synchronized (mLock) {
mCallbacks.add(Pair.create(callback, priority));
if (mActualDispatcher != null) {
- mActualDispatcher.registerOnBackInvokedCallback(priority, callback);
+ if (priority <= PRIORITY_SYSTEM) {
+ mActualDispatcher.registerSystemOnBackInvokedCallback(callback);
+ } else {
+ mActualDispatcher.registerOnBackInvokedCallback(priority, callback);
+ }
}
}
}
@@ -171,7 +175,16 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
return;
}
clearCallbacksOnDispatcher();
- mActualDispatcher = actualDispatcher;
+ if (actualDispatcher instanceof ProxyOnBackInvokedDispatcher) {
+ // We don't want to nest ProxyDispatchers, so if we are given on, we unwrap its
+ // actual dispatcher.
+ // This can happen when an Activity is recreated but the Window is preserved (e.g.
+ // when going from split-screen back to single screen)
+ mActualDispatcher =
+ ((ProxyOnBackInvokedDispatcher) actualDispatcher).mActualDispatcher;
+ } else {
+ mActualDispatcher = actualDispatcher;
+ }
transferCallbacksToDispatcher();
}
}
diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java
index f72164e1f53f..56e910769cb5 100644
--- a/core/java/android/window/TaskFragmentInfo.java
+++ b/core/java/android/window/TaskFragmentInfo.java
@@ -23,8 +23,10 @@ import static java.util.Objects.requireNonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Point;
+import android.graphics.Rect;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -66,7 +68,7 @@ public final class TaskFragmentInfo implements Parcelable {
private final List<IBinder> mActivities = new ArrayList<>();
/** Relative position of the fragment's top left corner in the parent container. */
- private final Point mPositionInParent;
+ private final Point mPositionInParent = new Point();
/**
* Whether the last running activity in the TaskFragment was finished due to clearing task while
@@ -80,21 +82,31 @@ public final class TaskFragmentInfo implements Parcelable {
*/
private final boolean mIsTaskFragmentClearedForPip;
+ /**
+ * The maximum {@link ActivityInfo.WindowLayout#minWidth} and
+ * {@link ActivityInfo.WindowLayout#minHeight} aggregated from the TaskFragment's child
+ * activities.
+ */
+ @NonNull
+ private final Point mMinimumDimensions = new Point();
+
/** @hide */
public TaskFragmentInfo(
@NonNull IBinder fragmentToken, @NonNull WindowContainerToken token,
@NonNull Configuration configuration, int runningActivityCount,
boolean isVisible, @NonNull List<IBinder> activities, @NonNull Point positionInParent,
- boolean isTaskClearedForReuse, boolean isTaskFragmentClearedForPip) {
+ boolean isTaskClearedForReuse, boolean isTaskFragmentClearedForPip,
+ @NonNull Point minimumDimensions) {
mFragmentToken = requireNonNull(fragmentToken);
mToken = requireNonNull(token);
mConfiguration.setTo(configuration);
mRunningActivityCount = runningActivityCount;
mIsVisible = isVisible;
mActivities.addAll(activities);
- mPositionInParent = requireNonNull(positionInParent);
+ mPositionInParent.set(positionInParent);
mIsTaskClearedForReuse = isTaskClearedForReuse;
mIsTaskFragmentClearedForPip = isTaskFragmentClearedForPip;
+ mMinimumDimensions.set(minimumDimensions);
}
@NonNull
@@ -154,6 +166,26 @@ public final class TaskFragmentInfo implements Parcelable {
}
/**
+ * Returns the minimum width this TaskFragment can be resized to.
+ * Client side must not {@link WindowContainerTransaction#setBounds(WindowContainerToken, Rect)}
+ * that {@link Rect#width()} is shorter than the reported value.
+ * @hide pending unhide
+ */
+ public int getMinimumWidth() {
+ return mMinimumDimensions.x;
+ }
+
+ /**
+ * Returns the minimum width this TaskFragment can be resized to.
+ * Client side must not {@link WindowContainerTransaction#setBounds(WindowContainerToken, Rect)}
+ * that {@link Rect#height()} is shorter than the reported value.
+ * @hide pending unhide
+ */
+ public int getMinimumHeight() {
+ return mMinimumDimensions.y;
+ }
+
+ /**
* Returns {@code true} if the parameters that are important for task fragment organizers are
* equal between this {@link TaskFragmentInfo} and {@param that}.
*/
@@ -170,7 +202,8 @@ public final class TaskFragmentInfo implements Parcelable {
&& mActivities.equals(that.mActivities)
&& mPositionInParent.equals(that.mPositionInParent)
&& mIsTaskClearedForReuse == that.mIsTaskClearedForReuse
- && mIsTaskFragmentClearedForPip == that.mIsTaskFragmentClearedForPip;
+ && mIsTaskFragmentClearedForPip == that.mIsTaskFragmentClearedForPip
+ && mMinimumDimensions.equals(that.mMinimumDimensions);
}
private TaskFragmentInfo(Parcel in) {
@@ -180,9 +213,10 @@ public final class TaskFragmentInfo implements Parcelable {
mRunningActivityCount = in.readInt();
mIsVisible = in.readBoolean();
in.readBinderList(mActivities);
- mPositionInParent = requireNonNull(in.readTypedObject(Point.CREATOR));
+ mPositionInParent.readFromParcel(in);
mIsTaskClearedForReuse = in.readBoolean();
mIsTaskFragmentClearedForPip = in.readBoolean();
+ mMinimumDimensions.readFromParcel(in);
}
/** @hide */
@@ -194,9 +228,10 @@ public final class TaskFragmentInfo implements Parcelable {
dest.writeInt(mRunningActivityCount);
dest.writeBoolean(mIsVisible);
dest.writeBinderList(mActivities);
- dest.writeTypedObject(mPositionInParent, flags);
+ mPositionInParent.writeToParcel(dest, flags);
dest.writeBoolean(mIsTaskClearedForReuse);
dest.writeBoolean(mIsTaskFragmentClearedForPip);
+ mMinimumDimensions.writeToParcel(dest, flags);
}
@NonNull
@@ -224,6 +259,7 @@ public final class TaskFragmentInfo implements Parcelable {
+ " positionInParent=" + mPositionInParent
+ " isTaskClearedForReuse=" + mIsTaskClearedForReuse
+ " isTaskFragmentClearedForPip" + mIsTaskFragmentClearedForPip
+ + " minimumDimensions" + mMinimumDimensions
+ "}";
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 61c844ac8170..66abe30d0123 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -300,6 +300,8 @@ public class ChooserActivity extends ResolverActivity implements
@VisibleForTesting
protected ChooserMultiProfilePagerAdapter mChooserMultiProfilePagerAdapter;
+ private final EnterTransitionAnimationDelegate mEnterTransitionAnimationDelegate =
+ new EnterTransitionAnimationDelegate();
private boolean mRemoveSharedElements = false;
@@ -383,7 +385,7 @@ public class ChooserActivity extends ResolverActivity implements
// transition animation.
getWindow().setWindowAnimations(0);
}
- startPostponedEnterTransition();
+ mEnterTransitionAnimationDelegate.markImagePreviewReady();
return true;
}
});
@@ -431,7 +433,7 @@ public class ChooserActivity extends ResolverActivity implements
mHideParentOnFail = false;
}
mRemoveSharedElements = true;
- startPostponedEnterTransition();
+ mEnterTransitionAnimationDelegate.markImagePreviewReady();
}
}
@@ -724,7 +726,7 @@ public class ChooserActivity extends ResolverActivity implements
mRemoveSharedElements = false;
}
});
- postponeEnterTransition();
+ mEnterTransitionAnimationDelegate.postponeTransition();
}
@Override
@@ -1242,6 +1244,9 @@ public class ChooserActivity extends ResolverActivity implements
if (layout != null) {
adjustPreviewWidth(getResources().getConfiguration().orientation, layout);
}
+ if (previewType != CONTENT_PREVIEW_IMAGE) {
+ mEnterTransitionAnimationDelegate.markImagePreviewReady();
+ }
return layout;
}
@@ -2514,88 +2519,94 @@ public class ChooserActivity extends ResolverActivity implements
if (mResolverDrawerLayout == null || gridAdapter == null) {
return;
}
+ int offset = calculateDrawerOffset(top, bottom, recyclerView, gridAdapter);
+ mResolverDrawerLayout.setCollapsibleHeightReserved(offset);
+ mEnterTransitionAnimationDelegate.markOffsetCalculated();
+ });
+ }
+ }
- final int bottomInset = mSystemWindowInsets != null
- ? mSystemWindowInsets.bottom : 0;
- int offset = bottomInset;
- int rowsToShow = gridAdapter.getSystemRowCount()
- + gridAdapter.getProfileRowCount()
- + gridAdapter.getServiceTargetRowCount()
- + gridAdapter.getCallerAndRankedTargetRowCount();
-
- // then this is most likely not a SEND_* action, so check
- // the app target count
- if (rowsToShow == 0) {
- rowsToShow = gridAdapter.getRowCount();
- }
+ private int calculateDrawerOffset(
+ int top, int bottom, RecyclerView recyclerView, ChooserGridAdapter gridAdapter) {
- // still zero? then use a default height and leave, which
- // can happen when there are no targets to show
- if (rowsToShow == 0 && !shouldShowStickyContentPreview()) {
- offset += getResources().getDimensionPixelSize(
- R.dimen.chooser_max_collapsed_height);
- mResolverDrawerLayout.setCollapsibleHeightReserved(offset);
- return;
- }
+ final int bottomInset = mSystemWindowInsets != null
+ ? mSystemWindowInsets.bottom : 0;
+ int offset = bottomInset;
+ int rowsToShow = gridAdapter.getSystemRowCount()
+ + gridAdapter.getProfileRowCount()
+ + gridAdapter.getServiceTargetRowCount()
+ + gridAdapter.getCallerAndRankedTargetRowCount();
- View stickyContentPreview = findViewById(R.id.content_preview_container);
- if (shouldShowStickyContentPreview() && isStickyContentPreviewShowing()) {
- offset += stickyContentPreview.getHeight();
- }
+ // then this is most likely not a SEND_* action, so check
+ // the app target count
+ if (rowsToShow == 0) {
+ rowsToShow = gridAdapter.getRowCount();
+ }
- if (shouldShowTabs()) {
- offset += findViewById(R.id.tabs).getHeight();
- }
+ // still zero? then use a default height and leave, which
+ // can happen when there are no targets to show
+ if (rowsToShow == 0 && !shouldShowStickyContentPreview()) {
+ offset += getResources().getDimensionPixelSize(
+ R.dimen.chooser_max_collapsed_height);
+ return offset;
+ }
- if (recyclerView.getVisibility() == View.VISIBLE) {
- int directShareHeight = 0;
- rowsToShow = Math.min(4, rowsToShow);
- boolean shouldShowExtraRow = shouldShowExtraRow(rowsToShow);
- mLastNumberOfChildren = recyclerView.getChildCount();
- for (int i = 0, childCount = recyclerView.getChildCount();
- i < childCount && rowsToShow > 0; i++) {
- View child = recyclerView.getChildAt(i);
- if (((GridLayoutManager.LayoutParams)
- child.getLayoutParams()).getSpanIndex() != 0) {
- continue;
- }
- int height = child.getHeight();
- offset += height;
- if (shouldShowExtraRow) {
- offset += height;
- }
+ View stickyContentPreview = findViewById(R.id.content_preview_container);
+ if (shouldShowStickyContentPreview() && isStickyContentPreviewShowing()) {
+ offset += stickyContentPreview.getHeight();
+ }
- if (gridAdapter.getTargetType(
- recyclerView.getChildAdapterPosition(child))
- == ChooserListAdapter.TARGET_SERVICE) {
- directShareHeight = height;
- }
- rowsToShow--;
- }
+ if (shouldShowTabs()) {
+ offset += findViewById(R.id.tabs).getHeight();
+ }
+
+ if (recyclerView.getVisibility() == View.VISIBLE) {
+ int directShareHeight = 0;
+ rowsToShow = Math.min(4, rowsToShow);
+ boolean shouldShowExtraRow = shouldShowExtraRow(rowsToShow);
+ mLastNumberOfChildren = recyclerView.getChildCount();
+ for (int i = 0, childCount = recyclerView.getChildCount();
+ i < childCount && rowsToShow > 0; i++) {
+ View child = recyclerView.getChildAt(i);
+ if (((GridLayoutManager.LayoutParams)
+ child.getLayoutParams()).getSpanIndex() != 0) {
+ continue;
+ }
+ int height = child.getHeight();
+ offset += height;
+ if (shouldShowExtraRow) {
+ offset += height;
+ }
- boolean isExpandable = getResources().getConfiguration().orientation
- == Configuration.ORIENTATION_PORTRAIT && !isInMultiWindowMode();
- if (directShareHeight != 0 && isSendAction(getTargetIntent())
- && isExpandable) {
- // make sure to leave room for direct share 4->8 expansion
- int requiredExpansionHeight =
- (int) (directShareHeight / DIRECT_SHARE_EXPANSION_RATE);
- int topInset = mSystemWindowInsets != null ? mSystemWindowInsets.top : 0;
- int minHeight = bottom - top - mResolverDrawerLayout.getAlwaysShowHeight()
- - requiredExpansionHeight - topInset - bottomInset;
-
- offset = Math.min(offset, minHeight);
- }
- } else {
- ViewGroup currentEmptyStateView = getActiveEmptyStateView();
- if (currentEmptyStateView.getVisibility() == View.VISIBLE) {
- offset += currentEmptyStateView.getHeight();
- }
+ if (gridAdapter.getTargetType(
+ recyclerView.getChildAdapterPosition(child))
+ == ChooserListAdapter.TARGET_SERVICE) {
+ directShareHeight = height;
}
+ rowsToShow--;
+ }
- mResolverDrawerLayout.setCollapsibleHeightReserved(Math.min(offset, bottom - top));
- });
+ boolean isExpandable = getResources().getConfiguration().orientation
+ == Configuration.ORIENTATION_PORTRAIT && !isInMultiWindowMode();
+ if (directShareHeight != 0 && isSendAction(getTargetIntent())
+ && isExpandable) {
+ // make sure to leave room for direct share 4->8 expansion
+ int requiredExpansionHeight =
+ (int) (directShareHeight / DIRECT_SHARE_EXPANSION_RATE);
+ int topInset = mSystemWindowInsets != null ? mSystemWindowInsets.top : 0;
+ int minHeight = bottom - top - mResolverDrawerLayout.getAlwaysShowHeight()
+ - requiredExpansionHeight - topInset - bottomInset;
+
+ offset = Math.min(offset, minHeight);
+ }
+ } else {
+ ViewGroup currentEmptyStateView = getActiveEmptyStateView();
+ if (currentEmptyStateView.getVisibility() == View.VISIBLE) {
+ offset += currentEmptyStateView.getHeight();
+ }
}
+
+ return Math.min(offset, bottom - top);
}
/**
@@ -3930,6 +3941,51 @@ public class ChooserActivity extends ResolverActivity implements
}
}
+ /**
+ * A helper class to track app's readiness for the scene transition animation.
+ * The app is ready when both the image is laid out and the drawer offset is calculated.
+ */
+ private class EnterTransitionAnimationDelegate implements View.OnLayoutChangeListener {
+ private boolean mPreviewReady = false;
+ private boolean mOffsetCalculated = false;
+
+ void postponeTransition() {
+ postponeEnterTransition();
+ }
+
+ void markImagePreviewReady() {
+ if (!mPreviewReady) {
+ mPreviewReady = true;
+ maybeStartListenForLayout();
+ }
+ }
+
+ void markOffsetCalculated() {
+ if (!mOffsetCalculated) {
+ mOffsetCalculated = true;
+ maybeStartListenForLayout();
+ }
+ }
+
+ private void maybeStartListenForLayout() {
+ if (mPreviewReady && mOffsetCalculated && mResolverDrawerLayout != null) {
+ if (mResolverDrawerLayout.isInLayout()) {
+ startPostponedEnterTransition();
+ } else {
+ mResolverDrawerLayout.addOnLayoutChangeListener(this);
+ mResolverDrawerLayout.requestLayout();
+ }
+ }
+ }
+
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ v.removeOnLayoutChangeListener(this);
+ startPostponedEnterTransition();
+ }
+ }
+
@Override
protected void maybeLogProfileChange() {
getChooserActivityLogger().logShareheetProfileChanged();
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
index aab1bc3aab5a..1ec5325623ec 100644
--- a/core/java/com/android/internal/app/ChooserListAdapter.java
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -36,9 +36,11 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
import android.service.chooser.ChooserTarget;
+import android.text.Layout;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.TextView;
import com.android.internal.R;
import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
@@ -102,6 +104,37 @@ public class ChooserListAdapter extends ResolverListAdapter {
private AppPredictor mAppPredictor;
private AppPredictor.Callback mAppPredictorCallback;
+ // For pinned direct share labels, if the text spans multiple lines, the TextView will consume
+ // the full width, even if the characters actually take up less than that. Measure the actual
+ // line widths and constrain the View's width based upon that so that the pin doesn't end up
+ // very far from the text.
+ private final View.OnLayoutChangeListener mPinTextSpacingListener =
+ new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ TextView textView = (TextView) v;
+ Layout layout = textView.getLayout();
+ if (layout != null) {
+ int textWidth = 0;
+ for (int line = 0; line < layout.getLineCount(); line++) {
+ textWidth = Math.max((int) Math.ceil(layout.getLineMax(line)),
+ textWidth);
+ }
+ int desiredWidth = textWidth + textView.getPaddingLeft()
+ + textView.getPaddingRight();
+ if (textView.getWidth() > desiredWidth) {
+ ViewGroup.LayoutParams params = textView.getLayoutParams();
+ params.width = desiredWidth;
+ textView.setLayoutParams(params);
+ // Need to wait until layout pass is over before requesting layout.
+ textView.post(() -> textView.requestLayout());
+ }
+ textView.removeOnLayoutChangeListener(this);
+ }
+ }
+ };
+
public ChooserListAdapter(Context context, List<Intent> payloadIntents,
Intent[] initialIntents, List<ResolveInfo> rList,
boolean filterLastUsed, ResolverListController resolverListController,
@@ -225,6 +258,7 @@ public class ChooserListAdapter extends ResolverListAdapter {
@Override
protected void onBindView(View view, TargetInfo info, int position) {
final ViewHolder holder = (ViewHolder) view.getTag();
+
if (info == null) {
holder.icon.setImageDrawable(
mContext.getDrawable(R.drawable.resolver_icon_placeholder));
@@ -274,6 +308,9 @@ public class ChooserListAdapter extends ResolverListAdapter {
holder.itemView.setBackground(holder.defaultItemViewBackground);
}
+ // Always remove the spacing listener, attach as needed to direct share targets below.
+ holder.text.removeOnLayoutChangeListener(mPinTextSpacingListener);
+
if (info instanceof MultiDisplayResolveInfo) {
// If the target is grouped show an indicator
Drawable bkg = mContext.getDrawable(R.drawable.chooser_group_background);
@@ -286,6 +323,7 @@ public class ChooserListAdapter extends ResolverListAdapter {
Drawable bkg = mContext.getDrawable(R.drawable.chooser_pinned_background);
holder.text.setPaddingRelative(bkg.getIntrinsicWidth() /* start */, 0, 0, 0);
holder.text.setBackground(bkg);
+ holder.text.addOnLayoutChangeListener(mPinTextSpacingListener);
} else {
holder.text.setBackground(null);
holder.text.setPaddingRelative(0, 0, 0, 0);
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index d72073d1ed74..7c08a7bbc826 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -158,6 +158,12 @@ public final class SystemUiDeviceConfigFlags {
public static final String PROPERTY_LOCATION_INDICATORS_ENABLED = "location_indicators_enabled";
/**
+ * Whether to show privacy chip for media projection.
+ */
+ public static final String PROPERTY_MEDIA_PROJECTION_INDICATORS_ENABLED =
+ "media_projection_indicators_enabled";
+
+ /**
* Whether to show old location indicator on all location accesses.
*/
public static final String PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED =
@@ -537,6 +543,11 @@ public final class SystemUiDeviceConfigFlags {
*/
public static final String TASK_MANAGER_ENABLED = "task_manager_enabled";
+ /**
+ * (boolean) Whether the task manager should show an attention grabbing dot when tasks changed.
+ */
+ public static final String TASK_MANAGER_SHOW_FOOTER_DOT = "task_manager_show_footer_dot";
+
/**
* (boolean) Whether the clipboard overlay is enabled.
diff --git a/core/java/com/android/internal/graphics/cam/Cam.java b/core/java/com/android/internal/graphics/cam/Cam.java
index 1ac5e5056c1e..1df85c389322 100644
--- a/core/java/com/android/internal/graphics/cam/Cam.java
+++ b/core/java/com/android/internal/graphics/cam/Cam.java
@@ -386,6 +386,13 @@ public class Cam {
// Yellows are very chromatic at L = 100, and blues are very chromatic at L = 0. All the
// other hues are white at L = 100, and black at L = 0. To preserve consistency for users of
// this system, it is better to simply return white at L* > 99, and black and L* < 0.
+ if (frame == Frame.DEFAULT) {
+ // If the viewing conditions are the same as the default sRGB-like viewing conditions,
+ // skip to using HctSolver: it uses geometrical insights to find the closest in-gamut
+ // match to hue/chroma/lstar.
+ return HctSolver.solveToInt(hue, chroma, lstar);
+ }
+
if (chroma < 1.0 || Math.round(lstar) <= 0.0 || Math.round(lstar) >= 100.0) {
return CamUtils.intFromLstar(lstar);
}
diff --git a/core/java/com/android/internal/graphics/cam/CamUtils.java b/core/java/com/android/internal/graphics/cam/CamUtils.java
index 13dafdba71f4..f54172996168 100644
--- a/core/java/com/android/internal/graphics/cam/CamUtils.java
+++ b/core/java/com/android/internal/graphics/cam/CamUtils.java
@@ -73,11 +73,123 @@ public final class CamUtils {
// used. It was derived using Schlomer's technique of transforming the xyY
// primaries to XYZ, then applying a correction to ensure mapping from sRGB
// 1, 1, 1 to the reference white point, D65.
- static final float[][] SRGB_TO_XYZ = {
- {0.41233895f, 0.35762064f, 0.18051042f},
- {0.2126f, 0.7152f, 0.0722f},
- {0.01932141f, 0.11916382f, 0.95034478f}
- };
+ static final double[][] SRGB_TO_XYZ =
+ new double[][] {
+ new double[] {0.41233895, 0.35762064, 0.18051042},
+ new double[] {0.2126, 0.7152, 0.0722},
+ new double[] {0.01932141, 0.11916382, 0.95034478},
+ };
+
+ static final double[][] XYZ_TO_SRGB =
+ new double[][] {
+ new double[] {
+ 3.2413774792388685, -1.5376652402851851, -0.49885366846268053,
+ },
+ new double[] {
+ -0.9691452513005321, 1.8758853451067872, 0.04156585616912061,
+ },
+ new double[] {
+ 0.05562093689691305, -0.20395524564742123, 1.0571799111220335,
+ },
+ };
+
+ /**
+ * The signum function.
+ *
+ * @return 1 if num > 0, -1 if num < 0, and 0 if num = 0
+ */
+ public static int signum(double num) {
+ if (num < 0) {
+ return -1;
+ } else if (num == 0) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
+ /**
+ * Converts an L* value to an ARGB representation.
+ *
+ * @param lstar L* in L*a*b*
+ * @return ARGB representation of grayscale color with lightness matching L*
+ */
+ public static int argbFromLstar(double lstar) {
+ double fy = (lstar + 16.0) / 116.0;
+ double fz = fy;
+ double fx = fy;
+ double kappa = 24389.0 / 27.0;
+ double epsilon = 216.0 / 24389.0;
+ boolean lExceedsEpsilonKappa = lstar > 8.0;
+ double y = lExceedsEpsilonKappa ? fy * fy * fy : lstar / kappa;
+ boolean cubeExceedEpsilon = fy * fy * fy > epsilon;
+ double x = cubeExceedEpsilon ? fx * fx * fx : lstar / kappa;
+ double z = cubeExceedEpsilon ? fz * fz * fz : lstar / kappa;
+ float[] whitePoint = WHITE_POINT_D65;
+ return argbFromXyz(x * whitePoint[0], y * whitePoint[1], z * whitePoint[2]);
+ }
+
+ /** Converts a color from ARGB to XYZ. */
+ public static int argbFromXyz(double x, double y, double z) {
+ double[][] matrix = XYZ_TO_SRGB;
+ double linearR = matrix[0][0] * x + matrix[0][1] * y + matrix[0][2] * z;
+ double linearG = matrix[1][0] * x + matrix[1][1] * y + matrix[1][2] * z;
+ double linearB = matrix[2][0] * x + matrix[2][1] * y + matrix[2][2] * z;
+ int r = delinearized(linearR);
+ int g = delinearized(linearG);
+ int b = delinearized(linearB);
+ return argbFromRgb(r, g, b);
+ }
+
+ /** Converts a color from linear RGB components to ARGB format. */
+ public static int argbFromLinrgb(double[] linrgb) {
+ int r = delinearized(linrgb[0]);
+ int g = delinearized(linrgb[1]);
+ int b = delinearized(linrgb[2]);
+ return argbFromRgb(r, g, b);
+ }
+
+ /** Converts a color from linear RGB components to ARGB format. */
+ public static int argbFromLinrgbComponents(double r, double g, double b) {
+ return argbFromRgb(delinearized(r), delinearized(g), delinearized(b));
+ }
+
+ /**
+ * Delinearizes an RGB component.
+ *
+ * @param rgbComponent 0.0 <= rgb_component <= 100.0, represents linear R/G/B channel
+ * @return 0 <= output <= 255, color channel converted to regular RGB space
+ */
+ public static int delinearized(double rgbComponent) {
+ double normalized = rgbComponent / 100.0;
+ double delinearized = 0.0;
+ if (normalized <= 0.0031308) {
+ delinearized = normalized * 12.92;
+ } else {
+ delinearized = 1.055 * Math.pow(normalized, 1.0 / 2.4) - 0.055;
+ }
+ return clampInt(0, 255, (int) Math.round(delinearized * 255.0));
+ }
+
+ /**
+ * Clamps an integer between two integers.
+ *
+ * @return input when min <= input <= max, and either min or max otherwise.
+ */
+ public static int clampInt(int min, int max, int input) {
+ if (input < min) {
+ return min;
+ } else if (input > max) {
+ return max;
+ }
+
+ return input;
+ }
+
+ /** Converts a color from RGB components to ARGB format. */
+ public static int argbFromRgb(int red, int green, int blue) {
+ return (255 << 24) | ((red & 255) << 16) | ((green & 255) << 8) | (blue & 255);
+ }
static int intFromLstar(float lstar) {
if (lstar < 1) {
@@ -126,9 +238,9 @@ public final class CamUtils {
final float r = linearized(Color.red(argb));
final float g = linearized(Color.green(argb));
final float b = linearized(Color.blue(argb));
- float[][] matrix = SRGB_TO_XYZ;
- float y = (r * matrix[1][0]) + (g * matrix[1][1]) + (b * matrix[1][2]);
- return y;
+ double[][] matrix = SRGB_TO_XYZ;
+ double y = (r * matrix[1][0]) + (g * matrix[1][1]) + (b * matrix[1][2]);
+ return (float) y;
}
@NonNull
@@ -137,19 +249,30 @@ public final class CamUtils {
final float g = linearized(Color.green(argb));
final float b = linearized(Color.blue(argb));
- float[][] matrix = SRGB_TO_XYZ;
- float x = (r * matrix[0][0]) + (g * matrix[0][1]) + (b * matrix[0][2]);
- float y = (r * matrix[1][0]) + (g * matrix[1][1]) + (b * matrix[1][2]);
- float z = (r * matrix[2][0]) + (g * matrix[2][1]) + (b * matrix[2][2]);
- return new float[]{x, y, z};
+ double[][] matrix = SRGB_TO_XYZ;
+ double x = (r * matrix[0][0]) + (g * matrix[0][1]) + (b * matrix[0][2]);
+ double y = (r * matrix[1][0]) + (g * matrix[1][1]) + (b * matrix[1][2]);
+ double z = (r * matrix[2][0]) + (g * matrix[2][1]) + (b * matrix[2][2]);
+ return new float[]{(float) x, (float) y, (float) z};
}
- static float yFromLstar(float lstar) {
- float ke = 8.0f;
+ /**
+ * Converts an L* value to a Y value.
+ *
+ * <p>L* in L*a*b* and Y in XYZ measure the same quantity, luminance.
+ *
+ * <p>L* measures perceptual luminance, a linear scale. Y in XYZ measures relative luminance, a
+ * logarithmic scale.
+ *
+ * @param lstar L* in L*a*b*
+ * @return Y in XYZ
+ */
+ public static double yFromLstar(double lstar) {
+ double ke = 8.0;
if (lstar > ke) {
- return (float) Math.pow(((lstar + 16.0) / 116.0), 3) * 100f;
+ return Math.pow((lstar + 16.0) / 116.0, 3.0) * 100.0;
} else {
- return lstar / (24389f / 27f) * 100f;
+ return lstar / (24389.0 / 27.0) * 100.0;
}
}
diff --git a/core/java/com/android/internal/graphics/cam/Frame.java b/core/java/com/android/internal/graphics/cam/Frame.java
index c422ad13c652..0ac7cbc2f60e 100644
--- a/core/java/com/android/internal/graphics/cam/Frame.java
+++ b/core/java/com/android/internal/graphics/cam/Frame.java
@@ -19,6 +19,8 @@ package com.android.internal.graphics.cam;
import android.annotation.NonNull;
import android.util.MathUtils;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
* The frame, or viewing conditions, where a color was seen. Used, along with a color, to create a
* color appearance model representing the color.
@@ -68,15 +70,18 @@ public final class Frame {
private final float mFlRoot;
private final float mZ;
- float getAw() {
+ @VisibleForTesting
+ public float getAw() {
return mAw;
}
- float getN() {
+ @VisibleForTesting
+ public float getN() {
return mN;
}
- float getNbb() {
+ @VisibleForTesting
+ public float getNbb() {
return mNbb;
}
@@ -92,8 +97,9 @@ public final class Frame {
return mNc;
}
+ @VisibleForTesting
@NonNull
- float[] getRgbD() {
+ public float[] getRgbD() {
return mRgbD;
}
@@ -101,7 +107,9 @@ public final class Frame {
return mFl;
}
- float getFlRoot() {
+ @VisibleForTesting
+ @NonNull
+ public float getFlRoot() {
return mFlRoot;
}
@@ -167,7 +175,7 @@ public final class Frame {
5.0 * adaptingLuminance));
// Intermediate factor, ratio of background relative luminance to white relative luminance
- float n = CamUtils.yFromLstar(backgroundLstar) / whitepoint[1];
+ float n = (float) CamUtils.yFromLstar(backgroundLstar) / whitepoint[1];
// Base exponential nonlinearity
// note Schlomer 2018 has a typo and uses 1.58, the correct factor is 1.48
diff --git a/core/java/com/android/internal/graphics/cam/HctSolver.java b/core/java/com/android/internal/graphics/cam/HctSolver.java
new file mode 100644
index 000000000000..d7a869185cd7
--- /dev/null
+++ b/core/java/com/android/internal/graphics/cam/HctSolver.java
@@ -0,0 +1,721 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.graphics.cam;
+
+/**
+ * An efficient algorithm for determining the closest sRGB color to a set of HCT coordinates,
+ * based on geometrical insights for finding intersections in linear RGB, CAM16, and L*a*b*.
+ *
+ * Algorithm identified and implemented by Tianguang Zhang.
+ * Copied from //java/com/google/ux/material/libmonet/hct on May 22 2022.
+ * ColorUtils/MathUtils functions that were required were added to CamUtils.
+ */
+public class HctSolver {
+ private HctSolver() {}
+
+ // Matrix used when converting from linear RGB to CAM16.
+ static final double[][] SCALED_DISCOUNT_FROM_LINRGB =
+ new double[][] {
+ new double[] {
+ 0.001200833568784504, 0.002389694492170889, 0.0002795742885861124,
+ },
+ new double[] {
+ 0.0005891086651375999, 0.0029785502573438758, 0.0003270666104008398,
+ },
+ new double[] {
+ 0.00010146692491640572, 0.0005364214359186694, 0.0032979401770712076,
+ },
+ };
+
+ // Matrix used when converting from CAM16 to linear RGB.
+ static final double[][] LINRGB_FROM_SCALED_DISCOUNT =
+ new double[][] {
+ new double[] {
+ 1373.2198709594231, -1100.4251190754821, -7.278681089101213,
+ },
+ new double[] {
+ -271.815969077903, 559.6580465940733, -32.46047482791194,
+ },
+ new double[] {
+ 1.9622899599665666, -57.173814538844006, 308.7233197812385,
+ },
+ };
+
+ // Weights for transforming a set of linear RGB coordinates to Y in XYZ.
+ static final double[] Y_FROM_LINRGB = new double[] {0.2126, 0.7152, 0.0722};
+
+ // Lookup table for plane in XYZ's Y axis (relative luminance) that corresponds to a given
+ // L* in L*a*b*. HCT's T is L*, and XYZ's Y is directly correlated to linear RGB, this table
+ // allows us to thus find the intersection between HCT and RGB, giving a solution to the
+ // RGB coordinates that correspond to a given set of HCT coordinates.
+ static final double[] CRITICAL_PLANES =
+ new double[] {
+ 0.015176349177441876,
+ 0.045529047532325624,
+ 0.07588174588720938,
+ 0.10623444424209313,
+ 0.13658714259697685,
+ 0.16693984095186062,
+ 0.19729253930674434,
+ 0.2276452376616281,
+ 0.2579979360165119,
+ 0.28835063437139563,
+ 0.3188300904430532,
+ 0.350925934958123,
+ 0.3848314933096426,
+ 0.42057480301049466,
+ 0.458183274052838,
+ 0.4976837250274023,
+ 0.5391024159806381,
+ 0.5824650784040898,
+ 0.6277969426914107,
+ 0.6751227633498623,
+ 0.7244668422128921,
+ 0.775853049866786,
+ 0.829304845476233,
+ 0.8848452951698498,
+ 0.942497089126609,
+ 1.0022825574869039,
+ 1.0642236851973577,
+ 1.1283421258858297,
+ 1.1946592148522128,
+ 1.2631959812511864,
+ 1.3339731595349034,
+ 1.407011200216447,
+ 1.4823302800086415,
+ 1.5599503113873272,
+ 1.6398909516233677,
+ 1.7221716113234105,
+ 1.8068114625156377,
+ 1.8938294463134073,
+ 1.9832442801866852,
+ 2.075074464868551,
+ 2.1693382909216234,
+ 2.2660538449872063,
+ 2.36523901573795,
+ 2.4669114995532007,
+ 2.5710888059345764,
+ 2.6777882626779785,
+ 2.7870270208169257,
+ 2.898822059350997,
+ 3.0131901897720907,
+ 3.1301480604002863,
+ 3.2497121605402226,
+ 3.3718988244681087,
+ 3.4967242352587946,
+ 3.624204428461639,
+ 3.754355295633311,
+ 3.887192587735158,
+ 4.022731918402185,
+ 4.160988767090289,
+ 4.301978482107941,
+ 4.445716283538092,
+ 4.592217266055746,
+ 4.741496401646282,
+ 4.893568542229298,
+ 5.048448422192488,
+ 5.20615066083972,
+ 5.3666897647573375,
+ 5.5300801301023865,
+ 5.696336044816294,
+ 5.865471690767354,
+ 6.037501145825082,
+ 6.212438385869475,
+ 6.390297286737924,
+ 6.571091626112461,
+ 6.7548350853498045,
+ 6.941541251256611,
+ 7.131223617812143,
+ 7.323895587840543,
+ 7.5195704746346665,
+ 7.7182615035334345,
+ 7.919981813454504,
+ 8.124744458384042,
+ 8.332562408825165,
+ 8.543448553206703,
+ 8.757415699253682,
+ 8.974476575321063,
+ 9.194643831691977,
+ 9.417930041841839,
+ 9.644347703669503,
+ 9.873909240696694,
+ 10.106627003236781,
+ 10.342513269534024,
+ 10.58158024687427,
+ 10.8238400726681,
+ 11.069304815507364,
+ 11.317986476196008,
+ 11.569896988756009,
+ 11.825048221409341,
+ 12.083451977536606,
+ 12.345119996613247,
+ 12.610063955123938,
+ 12.878295467455942,
+ 13.149826086772048,
+ 13.42466730586372,
+ 13.702830557985108,
+ 13.984327217668513,
+ 14.269168601521828,
+ 14.55736596900856,
+ 14.848930523210871,
+ 15.143873411576273,
+ 15.44220572664832,
+ 15.743938506781891,
+ 16.04908273684337,
+ 16.35764934889634,
+ 16.66964922287304,
+ 16.985093187232053,
+ 17.30399201960269,
+ 17.62635644741625,
+ 17.95219714852476,
+ 18.281524751807332,
+ 18.614349837764564,
+ 18.95068293910138,
+ 19.290534541298456,
+ 19.633915083172692,
+ 19.98083495742689,
+ 20.331304511189067,
+ 20.685334046541502,
+ 21.042933821039977,
+ 21.404114048223256,
+ 21.76888489811322,
+ 22.137256497705877,
+ 22.50923893145328,
+ 22.884842241736916,
+ 23.264076429332462,
+ 23.6469514538663,
+ 24.033477234264016,
+ 24.42366364919083,
+ 24.817520537484558,
+ 25.21505769858089,
+ 25.61628489293138,
+ 26.021211842414342,
+ 26.429848230738664,
+ 26.842203703840827,
+ 27.258287870275353,
+ 27.678110301598522,
+ 28.10168053274597,
+ 28.529008062403893,
+ 28.96010235337422,
+ 29.39497283293396,
+ 29.83362889318845,
+ 30.276079891419332,
+ 30.722335150426627,
+ 31.172403958865512,
+ 31.62629557157785,
+ 32.08401920991837,
+ 32.54558406207592,
+ 33.010999283389665,
+ 33.4802739966603,
+ 33.953417292456834,
+ 34.430438229418264,
+ 34.911345834551085,
+ 35.39614910352207,
+ 35.88485700094671,
+ 36.37747846067349,
+ 36.87402238606382,
+ 37.37449765026789,
+ 37.87891309649659,
+ 38.38727753828926,
+ 38.89959975977785,
+ 39.41588851594697,
+ 39.93615253289054,
+ 40.460400508064545,
+ 40.98864111053629,
+ 41.520882981230194,
+ 42.05713473317016,
+ 42.597404951718396,
+ 43.141702194811224,
+ 43.6900349931913,
+ 44.24241185063697,
+ 44.798841244188324,
+ 45.35933162437017,
+ 45.92389141541209,
+ 46.49252901546552,
+ 47.065252796817916,
+ 47.64207110610409,
+ 48.22299226451468,
+ 48.808024568002054,
+ 49.3971762874833,
+ 49.9904556690408,
+ 50.587870934119984,
+ 51.189430279724725,
+ 51.79514187861014,
+ 52.40501387947288,
+ 53.0190544071392,
+ 53.637271562750364,
+ 54.259673423945976,
+ 54.88626804504493,
+ 55.517063457223934,
+ 56.15206766869424,
+ 56.79128866487574,
+ 57.43473440856916,
+ 58.08241284012621,
+ 58.734331877617365,
+ 59.39049941699807,
+ 60.05092333227251,
+ 60.715611475655585,
+ 61.38457167773311,
+ 62.057811747619894,
+ 62.7353394731159,
+ 63.417162620860914,
+ 64.10328893648692,
+ 64.79372614476921,
+ 65.48848194977529,
+ 66.18756403501224,
+ 66.89098006357258,
+ 67.59873767827808,
+ 68.31084450182222,
+ 69.02730813691093,
+ 69.74813616640164,
+ 70.47333615344107,
+ 71.20291564160104,
+ 71.93688215501312,
+ 72.67524319850172,
+ 73.41800625771542,
+ 74.16517879925733,
+ 74.9167682708136,
+ 75.67278210128072,
+ 76.43322770089146,
+ 77.1981124613393,
+ 77.96744375590167,
+ 78.74122893956174,
+ 79.51947534912904,
+ 80.30219030335869,
+ 81.08938110306934,
+ 81.88105503125999,
+ 82.67721935322541,
+ 83.4778813166706,
+ 84.28304815182372,
+ 85.09272707154808,
+ 85.90692527145302,
+ 86.72564993000343,
+ 87.54890820862819,
+ 88.3767072518277,
+ 89.2090541872801,
+ 90.04595612594655,
+ 90.88742016217518,
+ 91.73345337380438,
+ 92.58406282226491,
+ 93.43925555268066,
+ 94.29903859396902,
+ 95.16341895893969,
+ 96.03240364439274,
+ 96.9059996312159,
+ 97.78421388448044,
+ 98.6670533535366,
+ 99.55452497210776,
+ };
+
+ /**
+ * Sanitizes a small enough angle in radians.
+ *
+ * @param angle An angle in radians; must not deviate too much from 0.
+ * @return A coterminal angle between 0 and 2pi.
+ */
+ static double sanitizeRadians(double angle) {
+ return (angle + Math.PI * 8) % (Math.PI * 2);
+ }
+
+ /**
+ * Delinearizes an RGB component, returning a floating-point number.
+ *
+ * @param rgbComponent 0.0 <= rgb_component <= 100.0, represents linear R/G/B channel
+ * @return 0.0 <= output <= 255.0, color channel converted to regular RGB space
+ */
+ static double trueDelinearized(double rgbComponent) {
+ double normalized = rgbComponent / 100.0;
+ double delinearized;
+ if (normalized <= 0.0031308) {
+ delinearized = normalized * 12.92;
+ } else {
+ delinearized = 1.055 * Math.pow(normalized, 1.0 / 2.4) - 0.055;
+ }
+ return delinearized * 255.0;
+ }
+
+ static double chromaticAdaptation(double component) {
+ double af = Math.pow(Math.abs(component), 0.42);
+ return CamUtils.signum(component) * 400.0 * af / (af + 27.13);
+ }
+
+ /**
+ * Returns the hue of a linear RGB color in CAM16.
+ *
+ * @param linrgb The linear RGB coordinates of a color.
+ * @return The hue of the color in CAM16, in radians.
+ */
+ static double hueOf(double[] linrgb) {
+ // Calculate scaled discount components using in-lined matrix multiplication to avoid
+ // an array allocation.
+ double[][] matrix = SCALED_DISCOUNT_FROM_LINRGB;
+ double[] row = linrgb;
+ double rD = linrgb[0] * matrix[0][0] + row[1] * matrix[0][1] + row[2] * matrix[0][2];
+ double gD = linrgb[0] * matrix[1][0] + row[1] * matrix[1][1] + row[2] * matrix[1][2];
+ double bD = linrgb[0] * matrix[2][0] + row[1] * matrix[2][1] + row[2] * matrix[2][2];
+
+ double rA = chromaticAdaptation(rD);
+ double gA = chromaticAdaptation(gD);
+ double bA = chromaticAdaptation(bD);
+ // redness-greenness
+ double a = (11.0 * rA + -12.0 * gA + bA) / 11.0;
+ // yellowness-blueness
+ double b = (rA + gA - 2.0 * bA) / 9.0;
+ return Math.atan2(b, a);
+ }
+
+ /**
+ * Cyclic order is the idea that 330° → 5° → 200° is in order, but, 180° → 270° → 210° is not.
+ * Visually, A B and C are angles, and they are in cyclic order if travelling from A to C
+ * in a way that increases angle (ex. counter-clockwise if +x axis = 0 degrees and +y = 90)
+ * means you must cross B.
+ * @param a first angle in possibly cyclic triplet
+ * @param b second angle in possibly cyclic triplet
+ * @param c third angle in possibly cyclic triplet
+ * @return true if B is between A and C
+ */
+ static boolean areInCyclicOrder(double a, double b, double c) {
+ double deltaAB = sanitizeRadians(b - a);
+ double deltaAC = sanitizeRadians(c - a);
+ return deltaAB < deltaAC;
+ }
+
+ /**
+ * Find an intercept using linear interpolation.
+ *
+ * @param source The starting number.
+ * @param mid The number in the middle.
+ * @param target The ending number.
+ * @return A number t such that lerp(source, target, t) = mid.
+ */
+ static double intercept(double source, double mid, double target) {
+ if (target == source) {
+ return target;
+ }
+ return (mid - source) / (target - source);
+ }
+
+ /**
+ * Linearly interpolate between two points in three dimensions.
+ *
+ * @param source three dimensions representing the starting point
+ * @param t the percentage to travel between source and target, from 0 to 1
+ * @param target three dimensions representing the end point
+ * @return three dimensions representing the point t percent from source to target.
+ */
+ static double[] lerpPoint(double[] source, double t, double[] target) {
+ return new double[] {
+ source[0] + (target[0] - source[0]) * t,
+ source[1] + (target[1] - source[1]) * t,
+ source[2] + (target[2] - source[2]) * t,
+ };
+ }
+
+ /**
+ * Intersects a segment with a plane.
+ *
+ * @param source The coordinates of point A.
+ * @param coordinate The R-, G-, or B-coordinate of the plane.
+ * @param target The coordinates of point B.
+ * @param axis The axis the plane is perpendicular with. (0: R, 1: G, 2: B)
+ * @return The intersection point of the segment AB with the plane R=coordinate, G=coordinate,
+ * or B=coordinate
+ */
+ static double[] setCoordinate(double[] source, double coordinate, double[] target, int axis) {
+ double t = intercept(source[axis], coordinate, target[axis]);
+ return lerpPoint(source, t, target);
+ }
+
+ /** Ensure X is between 0 and 100. */
+ static boolean isBounded(double x) {
+ return 0.0 <= x && x <= 100.0;
+ }
+
+ /**
+ * Returns the nth possible vertex of the polygonal intersection.
+ *
+ * @param y The Y value of the plane.
+ * @param n The zero-based index of the point. 0 <= n <= 11.
+ * @return The nth possible vertex of the polygonal intersection of the y plane and the RGB cube
+ * in linear RGB coordinates, if it exists. If the possible vertex lies outside of the cube,
+ * [-1.0, -1.0, -1.0] is returned.
+ */
+ static double[] nthVertex(double y, int n) {
+ double kR = Y_FROM_LINRGB[0];
+ double kG = Y_FROM_LINRGB[1];
+ double kB = Y_FROM_LINRGB[2];
+ double coordA = n % 4 <= 1 ? 0.0 : 100.0;
+ double coordB = n % 2 == 0 ? 0.0 : 100.0;
+ if (n < 4) {
+ double g = coordA;
+ double b = coordB;
+ double r = (y - g * kG - b * kB) / kR;
+ if (isBounded(r)) {
+ return new double[] {r, g, b};
+ } else {
+ return new double[] {-1.0, -1.0, -1.0};
+ }
+ } else if (n < 8) {
+ double b = coordA;
+ double r = coordB;
+ double g = (y - r * kR - b * kB) / kG;
+ if (isBounded(g)) {
+ return new double[] {r, g, b};
+ } else {
+ return new double[] {-1.0, -1.0, -1.0};
+ }
+ } else {
+ double r = coordA;
+ double g = coordB;
+ double b = (y - r * kR - g * kG) / kB;
+ if (isBounded(b)) {
+ return new double[] {r, g, b};
+ } else {
+ return new double[] {-1.0, -1.0, -1.0};
+ }
+ }
+ }
+
+ /**
+ * Finds the segment containing the desired color.
+ *
+ * @param y The Y value of the color.
+ * @param targetHue The hue of the color.
+ * @return A list of two sets of linear RGB coordinates, each corresponding to an endpoint of
+ * the segment containing the desired color.
+ */
+ static double[][] bisectToSegment(double y, double targetHue) {
+ double[] left = new double[] {-1.0, -1.0, -1.0};
+ double[] right = left;
+ double leftHue = 0.0;
+ double rightHue = 0.0;
+ boolean initialized = false;
+ boolean uncut = true;
+ for (int n = 0; n < 12; n++) {
+ double[] mid = nthVertex(y, n);
+ if (mid[0] < 0) {
+ continue;
+ }
+ double midHue = hueOf(mid);
+ if (!initialized) {
+ left = mid;
+ right = mid;
+ leftHue = midHue;
+ rightHue = midHue;
+ initialized = true;
+ continue;
+ }
+ if (uncut || areInCyclicOrder(leftHue, midHue, rightHue)) {
+ uncut = false;
+ if (areInCyclicOrder(leftHue, targetHue, midHue)) {
+ right = mid;
+ rightHue = midHue;
+ } else {
+ left = mid;
+ leftHue = midHue;
+ }
+ }
+ }
+ return new double[][] {left, right};
+ }
+
+ static int criticalPlaneBelow(double x) {
+ return (int) Math.floor(x - 0.5);
+ }
+
+ static int criticalPlaneAbove(double x) {
+ return (int) Math.ceil(x - 0.5);
+ }
+
+ /**
+ * Finds a color with the given Y and hue on the boundary of the cube.
+ *
+ * @param y The Y value of the color.
+ * @param targetHue The hue of the color.
+ * @return The desired color, in linear RGB coordinates.
+ */
+ static int bisectToLimit(double y, double targetHue) {
+ double[][] segment = bisectToSegment(y, targetHue);
+ double[] left = segment[0];
+ double leftHue = hueOf(left);
+ double[] right = segment[1];
+ for (int axis = 0; axis < 3; axis++) {
+ if (left[axis] != right[axis]) {
+ int lPlane = -1;
+ int rPlane = 255;
+ if (left[axis] < right[axis]) {
+ lPlane = criticalPlaneBelow(trueDelinearized(left[axis]));
+ rPlane = criticalPlaneAbove(trueDelinearized(right[axis]));
+ } else {
+ lPlane = criticalPlaneAbove(trueDelinearized(left[axis]));
+ rPlane = criticalPlaneBelow(trueDelinearized(right[axis]));
+ }
+ for (int i = 0; i < 8; i++) {
+ if (Math.abs(rPlane - lPlane) <= 1) {
+ break;
+ } else {
+ int mPlane = (int) Math.floor((lPlane + rPlane) / 2.0);
+ double midPlaneCoordinate = CRITICAL_PLANES[mPlane];
+ double[] mid = setCoordinate(left, midPlaneCoordinate, right, axis);
+ double midHue = hueOf(mid);
+ if (areInCyclicOrder(leftHue, targetHue, midHue)) {
+ right = mid;
+ rPlane = mPlane;
+ } else {
+ left = mid;
+ leftHue = midHue;
+ lPlane = mPlane;
+ }
+ }
+ }
+ }
+ }
+ return CamUtils.argbFromLinrgbComponents((left[0] + right[0]) / 2,
+ (left[1] + right[1]) / 2, (left[2] + right[2]) / 2);
+ }
+
+ /** Equation used in CAM16 conversion that removes the effect of chromatic adaptation. */
+ static double inverseChromaticAdaptation(double adapted) {
+ double adaptedAbs = Math.abs(adapted);
+ double base = Math.max(0, 27.13 * adaptedAbs / (400.0 - adaptedAbs));
+ return CamUtils.signum(adapted) * Math.pow(base, 1.0 / 0.42);
+ }
+
+ /**
+ * Finds a color with the given hue, chroma, and Y.
+ *
+ * @param hueRadians The desired hue in radians.
+ * @param chroma The desired chroma.
+ * @param y The desired Y.
+ * @return The desired color as a hexadecimal integer, if found; 0 otherwise.
+ */
+ static int findResultByJ(double hueRadians, double chroma, double y) {
+ // Initial estimate of j.
+ double j = Math.sqrt(y) * 11.0;
+ // ===========================================================
+ // Operations inlined from Cam16 to avoid repeated calculation
+ // ===========================================================
+ Frame viewingConditions = Frame.DEFAULT;
+ double tInnerCoeff = 1 / Math.pow(1.64 - Math.pow(0.29, viewingConditions.getN()), 0.73);
+ double eHue = 0.25 * (Math.cos(hueRadians + 2.0) + 3.8);
+ double p1 = eHue * (50000.0 / 13.0) * viewingConditions.getNc()
+ * viewingConditions.getNcb();
+ double hSin = Math.sin(hueRadians);
+ double hCos = Math.cos(hueRadians);
+ for (int iterationRound = 0; iterationRound < 5; iterationRound++) {
+ // ===========================================================
+ // Operations inlined from Cam16 to avoid repeated calculation
+ // ===========================================================
+ double jNormalized = j / 100.0;
+ double alpha = chroma == 0.0 || j == 0.0 ? 0.0 : chroma / Math.sqrt(jNormalized);
+ double t = Math.pow(alpha * tInnerCoeff, 1.0 / 0.9);
+ double acExponent = 1.0 / viewingConditions.getC() / viewingConditions.getZ();
+ double ac = viewingConditions.getAw() * Math.pow(jNormalized, acExponent);
+ double p2 = ac / viewingConditions.getNbb();
+ double gamma = 23.0 * (p2 + 0.305) * t / (23.0 * p1 + 11 * t * hCos + 108.0 * t * hSin);
+ double a = gamma * hCos;
+ double b = gamma * hSin;
+ double rA = (460.0 * p2 + 451.0 * a + 288.0 * b) / 1403.0;
+ double gA = (460.0 * p2 - 891.0 * a - 261.0 * b) / 1403.0;
+ double bA = (460.0 * p2 - 220.0 * a - 6300.0 * b) / 1403.0;
+ double rCScaled = inverseChromaticAdaptation(rA);
+ double gCScaled = inverseChromaticAdaptation(gA);
+ double bCScaled = inverseChromaticAdaptation(bA);
+ double[][] matrix = LINRGB_FROM_SCALED_DISCOUNT;
+ double linrgbR = rCScaled * matrix[0][0] + gCScaled * matrix[0][1]
+ + bCScaled * matrix[0][2];
+ double linrgbG = rCScaled * matrix[1][0] + gCScaled * matrix[1][1]
+ + bCScaled * matrix[1][2];
+ double linrgbB = rCScaled * matrix[2][0] + gCScaled * matrix[2][1]
+ + bCScaled * matrix[2][2];
+ // ===========================================================
+ // Operations inlined from Cam16 to avoid repeated calculation
+ // ===========================================================
+ if (linrgbR < 0 || linrgbG < 0 || linrgbB < 0) {
+ return 0;
+ }
+ double kR = Y_FROM_LINRGB[0];
+ double kG = Y_FROM_LINRGB[1];
+ double kB = Y_FROM_LINRGB[2];
+ double fnj = kR * linrgbR + kG * linrgbG + kB * linrgbB;
+ if (fnj <= 0) {
+ return 0;
+ }
+ if (iterationRound == 4 || Math.abs(fnj - y) < 0.002) {
+ if (linrgbR > 100.01 || linrgbG > 100.01 || linrgbB > 100.01) {
+ return 0;
+ }
+ return CamUtils.argbFromLinrgbComponents(linrgbR, linrgbG, linrgbB);
+ }
+ // Iterates with Newton method,
+ // Using 2 * fn(j) / j as the approximation of fn'(j)
+ j = j - (fnj - y) * j / (2 * fnj);
+ }
+ return 0;
+ }
+
+ /**
+ * Finds an sRGB color with the given hue, chroma, and L*, if possible.
+ *
+ * @param hueDegrees The desired hue, in degrees.
+ * @param chroma The desired chroma.
+ * @param lstar The desired L*.
+ * @return A hexadecimal representing the sRGB color. The color has sufficiently close hue,
+ * chroma, and L* to the desired values, if possible; otherwise, the hue and L* will be
+ * sufficiently close, and chroma will be maximized.
+ */
+ public static int solveToInt(double hueDegrees, double chroma, double lstar) {
+ if (chroma < 0.0001 || lstar < 0.0001 || lstar > 99.9999) {
+ return CamUtils.argbFromLstar(lstar);
+ }
+ hueDegrees = sanitizeDegreesDouble(hueDegrees);
+ double hueRadians = Math.toRadians(hueDegrees);
+ double y = CamUtils.yFromLstar(lstar);
+ int exactAnswer = findResultByJ(hueRadians, chroma, y);
+ if (exactAnswer != 0) {
+ return exactAnswer;
+ }
+ return bisectToLimit(y, hueRadians);
+ }
+
+ /**
+ * Sanitizes a degree measure as a floating-point number.
+ *
+ * @return a degree measure between 0.0 (inclusive) and 360.0 (exclusive).
+ */
+ public static double sanitizeDegreesDouble(double degrees) {
+ degrees = degrees % 360.0;
+ if (degrees < 0) {
+ degrees = degrees + 360.0;
+ }
+ return degrees;
+ }
+
+ /**
+ * Finds an sRGB color with the given hue, chroma, and L*, if possible.
+ *
+ * @param hueDegrees The desired hue, in degrees.
+ * @param chroma The desired chroma.
+ * @param lstar The desired L*.
+ * @return An CAM16 object representing the sRGB color. The color has sufficiently close hue,
+ * chroma, and L* to the desired values, if possible; otherwise, the hue and L* will be
+ * sufficiently close, and chroma will be maximized.
+ */
+ public static Cam solveToCam(double hueDegrees, double chroma, double lstar) {
+ return Cam.fromInt(solveToInt(hueDegrees, chroma, lstar));
+ }
+}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 65e7abf674c3..52fd7fec932e 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -53,6 +53,7 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_QS_TILE;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_DIALOG_OPEN;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_EXPAND_COLLAPSE_LOCK;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_HEADS_UP_APPEAR;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_HEADS_UP_DISAPPEAR;
@@ -75,6 +76,7 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__TAKE_SCREENSHOT;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__UNFOLD_ANIM;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_DIALOG_OPEN;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_SWITCH;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__VOLUME_CONTROL;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION;
@@ -202,6 +204,8 @@ public class InteractionJankMonitor {
public static final int CUJ_VOLUME_CONTROL = 55;
public static final int CUJ_BIOMETRIC_PROMPT_TRANSITION = 56;
public static final int CUJ_SETTINGS_TOGGLE = 57;
+ public static final int CUJ_SHADE_DIALOG_OPEN = 58;
+ public static final int CUJ_USER_DIALOG_OPEN = 59;
private static final int NO_STATSD_LOGGING = -1;
@@ -268,6 +272,8 @@ public class InteractionJankMonitor {
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__VOLUME_CONTROL,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__BIOMETRIC_PROMPT_TRANSITION,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_TOGGLE,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_DIALOG_OPEN,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_DIALOG_OPEN,
};
private static volatile InteractionJankMonitor sInstance;
@@ -346,6 +352,8 @@ public class InteractionJankMonitor {
CUJ_VOLUME_CONTROL,
CUJ_BIOMETRIC_PROMPT_TRANSITION,
CUJ_SETTINGS_TOGGLE,
+ CUJ_SHADE_DIALOG_OPEN,
+ CUJ_USER_DIALOG_OPEN,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
@@ -780,6 +788,10 @@ public class InteractionJankMonitor {
return "BIOMETRIC_PROMPT_TRANSITION";
case CUJ_SETTINGS_TOGGLE:
return "SETTINGS_TOGGLE";
+ case CUJ_SHADE_DIALOG_OPEN:
+ return "SHADE_DIALOG_OPEN";
+ case CUJ_USER_DIALOG_OPEN:
+ return "USER_DIALOG_OPEN";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 12571b1ef521..e258fc19a75f 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -342,7 +342,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
boolean mDecorFitsSystemWindows = true;
- private ProxyOnBackInvokedDispatcher mProxyOnBackInvokedDispatcher =
+ private final ProxyOnBackInvokedDispatcher mProxyOnBackInvokedDispatcher =
new ProxyOnBackInvokedDispatcher();
static class WindowManagerHolder {
@@ -378,6 +378,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// window, as we'll be skipping the addView in handleResumeActivity(), and
// the token will not be updated as for a new window.
getAttributes().token = preservedWindow.getAttributes().token;
+ mProxyOnBackInvokedDispatcher.setActualDispatcher(
+ preservedWindow.getOnBackInvokedDispatcher());
}
// Even though the device doesn't support picture-in-picture mode,
// an user can force using it through developer options.
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 634063a44b66..e93a7854f1cd 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -242,7 +242,8 @@ oneway interface IStatusBar
* Displays a text toast.
*/
void showToast(int uid, String packageName, IBinder token, CharSequence text,
- IBinder windowToken, int duration, @nullable ITransientNotificationCallback callback);
+ IBinder windowToken, int duration, @nullable ITransientNotificationCallback callback,
+ int displayId);
/**
* Cancels toast with token {@code token} in {@code packageName}.
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 90eeabb47e9a..1cdc10866f2c 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -929,7 +929,7 @@ public class ResolverDrawerLayout extends ViewGroup {
// Single-use layout; just ignore the mode and use available space.
// Clamp to maxWidth.
if (mMaxWidth >= 0) {
- widthSize = Math.min(widthSize, mMaxWidth);
+ widthSize = Math.min(widthSize, mMaxWidth + getPaddingLeft() + getPaddingRight());
}
final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
@@ -1008,8 +1008,9 @@ public class ResolverDrawerLayout extends ViewGroup {
View indicatorHost = null;
int ypos = mTopOffset;
- int leftEdge = getPaddingLeft();
- int rightEdge = width - getPaddingRight();
+ final int leftEdge = getPaddingLeft();
+ final int rightEdge = width - getPaddingRight();
+ final int widthAvailable = rightEdge - leftEdge;
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -1030,7 +1031,6 @@ public class ResolverDrawerLayout extends ViewGroup {
final int bottom = top + child.getMeasuredHeight();
final int childWidth = child.getMeasuredWidth();
- final int widthAvailable = rightEdge - leftEdge;
final int left = leftEdge + (widthAvailable - childWidth) / 2;
final int right = left + childWidth;
diff --git a/core/proto/android/server/windowmanagertransitiontrace.proto b/core/proto/android/server/windowmanagertransitiontrace.proto
new file mode 100644
index 000000000000..9429127b2f6e
--- /dev/null
+++ b/core/proto/android/server/windowmanagertransitiontrace.proto
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package com.android.server.wm.shell;
+
+import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
+
+option java_multiple_files = true;
+
+/* Represents a file full of transition entries.
+ Encoded, it should start with 0x9 0x57 0x49 0x4e 0x54 0x52 0x41 0x43 0x45 (.TRNTRACE), such
+ that it can be easily identified. */
+message TransitionTraceProto {
+
+ /* constant; MAGIC_NUMBER = (long) MAGIC_NUMBER_H << 32 | MagicNumber.MAGIC_NUMBER_L
+ (this is needed because enums have to be 32 bits and there's no nice way to put 64bit
+ constants into .proto files. */
+ enum MagicNumber {
+ INVALID = 0;
+ MAGIC_NUMBER_L = 0x544e5254; /* TRNT (little-endian ASCII) */
+ MAGIC_NUMBER_H = 0x45434152; /* RACE (little-endian ASCII) */
+ }
+
+ fixed64 magic_number = 1; /* Must be the first field, set to value in MagicNumber */
+ int64 timestamp = 2; /* The timestamp of when the trace was started. */
+ repeated Transition transition = 3;
+}
+
+message Transition {
+
+ enum State {
+ COLLECTING = 0;
+ PENDING = -1;
+ STARTED = 1;
+ PLAYING = 2;
+ ABORT = 3;
+ FINISHED = 4;
+ }
+
+ int32 id = 1;
+ int32 transition_type = 2;
+ int64 timestamp = 3;
+ State state = 5;
+ int32 flags = 6;
+ repeated ChangeInfo change = 7;
+}
+
+message ChangeInfo {
+ com.android.server.wm.IdentifierProto window_identifier = 1;
+ int32 transit_mode = 2;
+ bool has_changed = 3;
+ int32 change_flags = 4;
+}
diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml
index 1d67570cf485..f816d0c41349 100644
--- a/core/res/res/drawable-nodpi/platlogo.xml
+++ b/core/res/res/drawable-nodpi/platlogo.xml
@@ -13,24 +13,23 @@ Copyright (C) 2021 The Android Open Source Project
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
+<vector android:height="128dp"
android:width="128dp"
- android:height="128dp"
- android:viewportWidth="128"
- android:viewportHeight="128">
- <path
- android:pathData="M64,64m-64,0a64,64 0,1 1,128 0a64,64 0,1 1,-128 0"
- android:fillColor="@android:color/system_accent3_500"/>
- <path
- android:pathData="M32.5,34.15a10,10 0,0 1,9.94 10V93.85"
- android:strokeWidth="4"
- android:fillColor="#00000000"
- android:strokeColor="#fff"
- android:strokeLineCap="round"/>
- <path
- android:pathData="M95.5,93.85H55.71V83.9A19.9,19.9 0,0 1,75.61 64h10a9.94,9.94 0,0 0,9.94 -10,19.9 19.9,0 0,0 -38.69,-6.56A20.77,20.77 0,0 0,56 50.73"
- android:strokeWidth="4"
- android:fillColor="#00000000"
- android:strokeColor="#fff"
- android:strokeLineCap="round"/>
+ android:viewportHeight="24"
+ android:viewportWidth="24"
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <path
+ android:pathData="M11 0.51a2.06 2.06 0 0 1 2 0l0.58 0.37a4.15 4.15 0 0 0 2.23 0.55l0.69-0.06a2.07 2.07 0 0 1 1.81 0.95l0.33 0.6a4.14 4.14 0 0 0 1.72 1.52l0.64 0.27a2 2 0 0 1 1.16 1.68l0 0.69A4.12 4.12 0 0 0 23 9.23l0.44 0.53a2.06 2.06 0 0 1 0.24 2l-0.3 0.62a4.14 4.14 0 0 0-0.27 2.28l0.14 0.68a2.08 2.08 0 0 1-0.72 1.91l-0.56 0.41a4 4 0 0 0-1.3 1.89l-0.19 0.66A2.06 2.06 0 0 1 19 21.58l-0.68 0.11a4.09 4.09 0 0 0-2 1.07l-0.48 0.5a2.08 2.08 0 0 1-2 0.49l-0.65-0.23a4.28 4.28 0 0 0-2.3 0l-0.65 0.23a2.08 2.08 0 0 1-2-0.49l-0.48-0.5a4 4 0 0 0-2-1.07L5 21.58A2.06 2.06 0 0 1 3.5 20.23l-0.19-0.66A4 4 0 0 0 2 17.68l-0.56-0.41a2.08 2.08 0 0 1-0.72-1.91l0.14-0.68A4.14 4.14 0 0 0 0.6 12.4l-0.3-0.62a2.06 2.06 0 0 1 0.24-2L1 9.23A4.16 4.16 0 0 0 1.8 7.08l0-0.69A2 2 0 0 1 3 4.71l0.64-0.27A4.14 4.14 0 0 0 5.34 2.92l0.33-0.6a2.07 2.07 0 0 1 1.81-0.95l0.69 0.06A4.15 4.15 0 0 0 10.4 0.88Z"
+ android:fillColor="@android:color/system_accent3_400"
+ />
+ <path
+ android:pathData="M12.34 6.53h4.05l-2 4.05a3.95 3.95 0 0 1-0.57 7.85 4.1 4.1 0 0 1-1.45-0.27"
+ android:strokeColor="@android:color/system_accent1_800"
+ android:strokeWidth="2"/>
+ <path
+ android:pathData="M12.34 6.53h4.05l-2 4.05a3.95 3.95 0 0 1-0.57 7.85 4.1 4.1 0 0 1-1.45-0.27"
+ android:strokeColor="@android:color/system_neutral1_100"
+ android:strokeWidth="0.5"/>
+
</vector>
+
diff --git a/core/res/res/layout/log_access_user_consent_dialog_permission.xml b/core/res/res/layout/log_access_user_consent_dialog_permission.xml
index 1a395b9fc30f..3da14c8f1886 100644
--- a/core/res/res/layout/log_access_user_consent_dialog_permission.xml
+++ b/core/res/res/layout/log_access_user_consent_dialog_permission.xml
@@ -16,77 +16,86 @@
** limitations under the License.
*/
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="380dp"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:gravity="center"
- android:paddingLeft="24dp"
- android:paddingRight="24dp"
- android:paddingTop="24dp"
- android:paddingBottom="24dp">
-
- <ImageView
- android:id="@+id/log_access_image_view"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:layout_marginBottom="16dp"
- android:src="@drawable/ic_doc_document"
- tools:layout_editor_absoluteX="148dp"
- tools:layout_editor_absoluteY="35dp"
- android:gravity="center" />
-
- <TextView
- android:id="@+id/log_access_dialog_title"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_marginBottom="32dp"
- android:text="@string/log_access_confirmation_title"
- android:textAppearance="@style/AllowLogAccess"
- android:textColor="?android:attr/textColorPrimary"
- android:gravity="center" />
-
- <TextView
- android:id="@+id/log_access_dialog_body"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_marginBottom="40dp"
- android:text="@string/log_access_confirmation_body"
- android:textAppearance="@style/PrimaryAllowLogAccess"
- android:textColor="?android:attr/textColorPrimary"
- android:gravity="center" />
-
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="380dp"
+ android:layout_height="match_parent"
+ android:clipToPadding="false">
<LinearLayout
- android:orientation="vertical"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <Button
- android:id="@+id/log_access_dialog_allow_button"
- android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:paddingLeft="24dp"
+ android:paddingRight="24dp"
+ android:paddingTop="24dp"
+ android:paddingBottom="24dp">
+
+ <ImageView
+ android:id="@+id/log_access_image_view"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_marginBottom="16dp"
+ android:src="@drawable/ic_doc_document"
+ tools:layout_editor_absoluteX="148dp"
+ tools:layout_editor_absoluteY="35dp"
+ android:gravity="center" />
+
+ <TextView
+ android:id="@+id/log_access_dialog_title"
android:layout_height="wrap_content"
- android:text="@string/log_access_confirmation_allow"
- style="@style/PermissionGrantButtonTop"
- android:textAppearance="@style/PermissionGrantButtonTextAppearance"
- android:layout_marginBottom="5dp"
- android:layout_centerHorizontal="true"
- android:layout_alignParentTop="true"
- android:layout_alignParentBottom="true"
- android:clipToOutline="true"
+ android:layout_width="wrap_content"
+ android:layout_marginBottom="32dp"
+ android:text="@string/log_access_confirmation_title"
+ android:textAppearance="@style/AllowLogAccess"
+ android:textColor="?android:attr/textColorPrimary"
android:gravity="center" />
- <Button
- android:id="@+id/log_access_dialog_deny_button"
- android:layout_width="match_parent"
+ <TextView
+ android:id="@+id/log_access_dialog_body"
android:layout_height="wrap_content"
- android:text="@string/log_access_confirmation_deny"
- style="@style/PermissionGrantButtonBottom"
- android:textAppearance="@style/PermissionGrantButtonTextAppearance"
- android:layout_centerHorizontal="true"
- android:layout_alignParentTop="true"
- android:layout_alignParentBottom="true"
- android:clipToOutline="true"
+ android:layout_width="wrap_content"
+ android:layout_marginBottom="40dp"
+ android:text="@string/log_access_confirmation_body"
+ android:textAppearance="@style/PrimaryAllowLogAccess"
+ android:textColor="?android:attr/textColorPrimary"
android:gravity="center" />
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <Button
+ android:id="@+id/log_access_dialog_allow_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/log_access_confirmation_allow"
+ style="@style/PermissionGrantButtonTop"
+ android:textAppearance="@style/PermissionGrantButtonTextAppearance"
+ android:layout_marginBottom="5dp"
+ android:layout_centerHorizontal="true"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentBottom="true"
+ android:clipToOutline="true"
+ android:gravity="center" />
+
+ <Button
+ android:id="@+id/log_access_dialog_deny_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/log_access_confirmation_deny"
+ style="@style/PermissionGrantButtonBottom"
+ android:textAppearance="@style/PermissionGrantButtonTextAppearance"
+ android:layout_centerHorizontal="true"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentBottom="true"
+ android:clipToOutline="true"
+ android:gravity="center" />
+ </LinearLayout>
</LinearLayout>
-</LinearLayout> \ No newline at end of file
+</ScrollView>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 80d228c68eed..41531ebd7f0d 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1927,7 +1927,7 @@
<string name="language_selection_title" msgid="52674936078683285">"إضافة لغة"</string>
<string name="country_selection_title" msgid="5221495687299014379">"تفضيل المنطقة"</string>
<string name="search_language_hint" msgid="7004225294308793583">"اكتب اسم اللغة"</string>
- <string name="language_picker_section_suggested" msgid="6556199184638990447">"المناطق المقترحة"</string>
+ <string name="language_picker_section_suggested" msgid="6556199184638990447">"اللغات المقترَحة"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"جميع اللغات"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"كل المناطق"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"البحث"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 921b12126355..9344e52841d3 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1695,7 +1695,7 @@
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Funktionen auswählen, die du mit der Schaltfläche \"Bedienungshilfen\" verwenden möchtest"</string>
<string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Funktionen für Verknüpfung mit Lautstärketaste auswählen"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> wurde deaktiviert"</string>
- <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Verknüpfungen bearbeiten"</string>
+ <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Kurzbefehle bearbeiten"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Fertig"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Verknüpfung deaktivieren"</string>
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Verknüpfung verwenden"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 773759c2f775..51b221924587 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -2076,7 +2076,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Aceptar"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desactivar"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Más información"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Las notificaciones mejoradas reemplazaron a las notificaciones adaptables en Android 12. Esta función muestra respuestas y acciones sugeridas, y organiza tus notificaciones.\n\nLas notificaciones mejoradas pueden acceder a todo el contenido de notificaciones, lo que incluye información personal, como nombres de contactos y mensajes. También puede descartar o responder notificaciones (como atender llamadas) y controlar la función No interrumpir."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Las notificaciones mejoradas reemplazaron a las notificaciones adaptables en Android 12. Esta función muestra respuestas y acciones sugeridas, y organiza tus notificaciones.\n\nLas notificaciones mejoradas pueden acceder a todo el contenido de notificaciones, lo que incluye información personal, como nombres de contactos y mensajes. También puede descartar o responder notificaciones (como contestar llamadas) y controlar la función No interrumpir."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificación de información del modo de Rutinas"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Es posible que la batería se agote antes de la carga habitual"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Se activó el Ahorro de batería para extender la duración de la batería"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 08a62e4c9a81..889ef9cd6613 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -91,7 +91,7 @@
<string name="notification_channel_call_forward" msgid="8230490317314272406">"કૉલ ફૉર્વર્ડિંગ"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"કટોકટી કૉલબૅક મોડ"</string>
<string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"મોબાઇલ ડેટાની સ્થિતિ"</string>
- <string name="notification_channel_sms" msgid="1243384981025535724">"SMS સંદેશા"</string>
+ <string name="notification_channel_sms" msgid="1243384981025535724">"SMS મેસેજ"</string>
<string name="notification_channel_voice_mail" msgid="8457433203106654172">"વૉઇસમેઇલ સંદેશા"</string>
<string name="notification_channel_wfc" msgid="9048240466765169038">"વાઇ-ફાઇ કૉલિંગ"</string>
<string name="notification_channel_sim" msgid="5098802350325677490">"સિમનું સ્ટેટસ"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 97bd3fbc98b3..8d8d792ce008 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -312,7 +312,7 @@
<string name="permgrouplab_readMediaVisual" msgid="4724874717811908660">"ಫೋಟೋಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳು"</string>
<string name="permgroupdesc_readMediaVisual" msgid="4080463241903508688">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಫೋಟೋಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
<string name="permgrouplab_microphone" msgid="2480597427667420076">"ಮೈಕ್ರೋಫೋನ್‌"</string>
- <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ಆಡಿಯೊ ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string>
+ <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ಆಡಿಯೋ ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string>
<string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"ದೈಹಿಕ ಚಟುವಟಿಕೆ"</string>
<string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"ನಿಮ್ಮ ದೈಹಿಕ ಚಟುವಟಿಕೆಯನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
<string name="permgrouplab_camera" msgid="9090413408963547706">"ಕ್ಯಾಮರಾ"</string>
@@ -445,12 +445,12 @@
<string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"ಈ ಆ್ಯಪ್ ಬಳಕೆಯಲ್ಲಿರುವಾಗ ನಿಮ್ಮ ಅಂದಾಜು ಸ್ಥಳವನ್ನು, ಸ್ಥಳ ಸೇವೆಗಳಿಂದ ಪಡೆಯಬಹುದು. ಆ್ಯಪ್ ನಿಮ್ಮ ಸ್ಥಳವನ್ನು ಪಡೆಯಲು ನಿಮ್ಮ ಸಾಧನಕ್ಕಾಗಿ ಸ್ಥಳ ಸೇವೆಗಳನ್ನು ಆನ್ ಮಾಡಬೇಕು."</string>
<string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಸ್ಥಳವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
<string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"ಈ ಆ್ಯಪ್ ಬಳಕೆಯಲ್ಲಿಲ್ಲದಿರುವಾಗಲೂ ಸಹ ಸ್ಥಳವನ್ನು ಯಾವುದೇ ಸಮಯದಲ್ಲಾದರೂ ಪ್ರವೇಶಿಸಬಹುದು."</string>
- <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"ನಿಮ್ಮ ಆಡಿಯೊ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಿ"</string>
- <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"ವಾಲ್ಯೂಮ್ ರೀತಿಯ ಮತ್ತು ಔಟ್‍‍ಪುಟ್‍‍ಗಾಗಿ ಯಾವ ಸ್ಪೀಕರ್ ಬಳಸಬೇಕು ಎಂಬ ರೀತಿಯ ಜಾಗತಿಕ ಆಡಿಯೊ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ."</string>
- <string name="permlab_recordAudio" msgid="1208457423054219147">"ಆಡಿಯೊ ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string>
+ <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"ನಿಮ್ಮ ಆಡಿಯೋ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಿ"</string>
+ <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"ವಾಲ್ಯೂಮ್ ರೀತಿಯ ಮತ್ತು ಔಟ್‍‍ಪುಟ್‍‍ಗಾಗಿ ಯಾವ ಸ್ಪೀಕರ್ ಬಳಸಬೇಕು ಎಂಬ ರೀತಿಯ ಜಾಗತಿಕ ಆಡಿಯೋ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ."</string>
+ <string name="permlab_recordAudio" msgid="1208457423054219147">"ಆಡಿಯೋ ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string>
<string name="permdesc_recordAudio" msgid="5857246765327514062">"ಆ್ಯಪ್ ಬಳಕೆಯಲ್ಲಿರುವಾಗ ಈ ಆ್ಯಪ್ ಮೈಕ್ರೊಫೋನ್ ಬಳಸಿ ಆಡಿಯೊವನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಬಹುದು."</string>
<string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಆಡಿಯೊವನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string>
- <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"ಈ ಆ್ಯಪ್ ಮೈಕ್ರೋಫೋನ್ ಬಳಸುವ ಮೂಲಕ ಯಾವುದೇ ಸಮಯದಲ್ಲಾದರೂ ಆಡಿಯೊ ರೆಕಾರ್ಡ್ ಮಾಡಬಹುದು."</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"ಈ ಆ್ಯಪ್ ಮೈಕ್ರೋಫೋನ್ ಬಳಸುವ ಮೂಲಕ ಯಾವುದೇ ಸಮಯದಲ್ಲಾದರೂ ಆಡಿಯೋ ರೆಕಾರ್ಡ್ ಮಾಡಬಹುದು."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"ಸಿಮ್‌ಗೆ ಆಜ್ಞೆಗಳನ್ನು ಕಳುಹಿಸಿ"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"ಸಿಮ್‌ ಗೆ ಆದೇಶಗಳನ್ನು ಕಳುಹಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಇದು ತುಂಬಾ ಅಪಾಯಕಾರಿ."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ದೈಹಿಕ ಚಟುವಟಿಕೆಯನ್ನು ಗುರುತಿಸಿ"</string>
@@ -1614,7 +1614,7 @@
<string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ಹೆಡ್‌ಫೋನ್‌ಗಳು"</string>
<string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
<string name="default_audio_route_category_name" msgid="5241740395748134483">"ಸಿಸ್ಟಂ"</string>
- <string name="bluetooth_a2dp_audio_route_name" msgid="4214648773120426288">"ಬ್ಲೂಟೂತ್‌ ಆಡಿಯೊ"</string>
+ <string name="bluetooth_a2dp_audio_route_name" msgid="4214648773120426288">"ಬ್ಲೂಟೂತ್‌ ಆಡಿಯೋ"</string>
<string name="wireless_display_route_description" msgid="8297563323032966831">"ವಯರ್‌ಲೆಸ್ ಪ್ರದರ್ಶನ"</string>
<string name="media_route_button_content_description" msgid="2299223698196869956">"ಪಾತ್ರ"</string>
<string name="media_route_chooser_title" msgid="6646594924991269208">"ಸಾಧನಕ್ಕೆ ಸಂಪರ್ಕಿಸಿ"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 7e0f9084cce2..c735ff5361d1 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -301,7 +301,7 @@
<string name="permgroupdesc_contacts" msgid="9163927941244182567">"നിങ്ങളുടെ കോൺടാക്റ്റുകൾ ആക്‌സസ്സ് ചെയ്യുക"</string>
<string name="permgrouplab_location" msgid="1858277002233964394">"ലൊക്കേഷൻ"</string>
<string name="permgroupdesc_location" msgid="1995955142118450685">"ഈ ഉപകരണത്തിന്റെ ലൊക്കേഷൻ ആക്സസ് ചെയ്യാൻ"</string>
- <string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendar"</string>
+ <string name="permgrouplab_calendar" msgid="6426860926123033230">"കലണ്ടർ"</string>
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"നിങ്ങളുടെ കലണ്ടർ ആക്‌സസ്സ് ചെയ്യുക"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS സന്ദേശങ്ങൾ അയയ്‌ക്കുകയും കാണുകയും ചെയ്യുക"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index e28c3c91df37..d70fc9b88cfe 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1683,7 +1683,7 @@
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"ଚାଲୁ କରନ୍ତୁ ନାହିଁ"</string>
<string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"ଚାଲୁ ଅଛି"</string>
<string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"ବନ୍ଦ ଅଛି"</string>
- <string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g>କୁ ଆପଣଙ୍କ ଡିଭାଇସର ସମ୍ପୂର୍ଣ୍ଣ ନିୟନ୍ତ୍ରଣର ଅନୁମତି ଦେବେ?"</string>
+ <string name="accessibility_enable_service_title" msgid="3931558336268541484">"ଆପଣଙ୍କ ଡିଭାଇସର ସମ୍ପୂର୍ଣ୍ଣ ନିୟନ୍ତ୍ରଣ କରିବାକୁ <xliff:g id="SERVICE">%1$s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string>
<string name="accessibility_service_warning_description" msgid="291674995220940133">"ଯେଉଁ ଆପ୍ସ ଆପଣଙ୍କୁ ଆକ୍ସେସିବିଲିଟୀ ଆବଶ୍ୟକତାରେ ସହାୟତା କରେ, ସେହି ଆପ୍ସ ପାଇଁ ସମ୍ପୂର୍ଣ୍ଣ ନିୟନ୍ତ୍ରଣ ଉପଯୁକ୍ତ ଅଟେ, କିନ୍ତୁ ଅଧିକାଂଶ ଆପ୍ସ ପାଇଁ ଉପଯୁକ୍ତ ନୁହେଁ।"</string>
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"ଭ୍ୟୁ ଏବଂ ସ୍କ୍ରିନ୍‍ ନିୟନ୍ତ୍ରଣ"</string>
<string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"ଏହା ସ୍କ୍ରିନ୍‍ର ସମସ୍ତ ବିଷୟବସ୍ତୁ ପଢ଼ିପାରେ ଏବଂ ଅନ୍ୟ ଆପ୍ସରେ ବିଷୟବସ୍ତୁ ପ୍ରଦର୍ଶନ କରିପାରେ।"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 76f8a4ece29d..029099b65e8d 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -355,8 +355,8 @@
<string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"Permite que o app remova atalhos da tela inicial sem a intervenção do usuário."</string>
<string name="permlab_processOutgoingCalls" msgid="4075056020714266558">"redirecionar as chamadas efetuadas"</string>
<string name="permdesc_processOutgoingCalls" msgid="7833149750590606334">"Permite que o app veja o número discado ao realizar uma chamada, com a opção de redirecionar a chamada para outro número ou abortá-la."</string>
- <string name="permlab_answerPhoneCalls" msgid="4131324833663725855">"atender chamadas telefônicas"</string>
- <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"Permite que o app atenda uma chamada recebida."</string>
+ <string name="permlab_answerPhoneCalls" msgid="4131324833663725855">"atender ligações telefônicas"</string>
+ <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"Permite que o app atenda uma ligação recebida."</string>
<string name="permlab_receiveSms" msgid="505961632050451881">"receber mensagens de texto (SMS)"</string>
<string name="permdesc_receiveSms" msgid="1797345626687832285">"Permite que o app receba e processe mensagens SMS. Isso significa que o app pode monitorar ou excluir mensagens enviadas para o dispositivo sem mostrá-las para você."</string>
<string name="permlab_receiveMms" msgid="4000650116674380275">"receber mensagens de texto (MMS)"</string>
@@ -420,7 +420,7 @@
<string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"Permite que o app modifique os dados sobre os contatos armazenados no dispositivo Android TV. Essa permissão autoriza os apps a excluírem dados de contato."</string>
<string name="permdesc_writeContacts" product="default" msgid="8304795696237065281">"Permite que o app modifique os dados sobre os contatos armazenados no smartphone. Essa permissão autoriza os apps a excluírem dados de contato."</string>
<string name="permlab_readCallLog" msgid="1739990210293505948">"ler registro de chamadas"</string>
- <string name="permdesc_readCallLog" msgid="8964770895425873433">"Este app pode ler seu histórico de chamadas."</string>
+ <string name="permdesc_readCallLog" msgid="8964770895425873433">"Este app pode ler seu histórico de ligações."</string>
<string name="permlab_writeCallLog" msgid="670292975137658895">"salvar no registo de chamadas"</string>
<string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"Permite que o app modifique o registro de chamadas de seu tablet, incluindo dados sobre chamadas recebidas e efetuadas. Apps maliciosos podem usar esta permissão para apagar ou modificar seu registro de chamadas."</string>
<string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"Permite que o app modifique o registro de chamadas do seu dispositivo Android TV, incluindo dados sobre chamadas recebidas e realizadas. Apps maliciosos podem usar essa permissão para apagar ou modificar seu registro de chamadas."</string>
@@ -1912,7 +1912,7 @@
<string name="call_notification_hang_up_action" msgid="9130720590159188131">"Desligar"</string>
<string name="call_notification_incoming_text" msgid="6143109825406638201">"Chamada recebida"</string>
<string name="call_notification_ongoing_text" msgid="3880832933933020875">"Chamada em andamento"</string>
- <string name="call_notification_screening_text" msgid="8396931408268940208">"Filtrando uma chamada recebida"</string>
+ <string name="call_notification_screening_text" msgid="8396931408268940208">"Filtrando uma ligação recebida"</string>
<string name="default_notification_channel_label" msgid="3697928973567217330">"Sem classificação"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Você definiu a importância dessas notificações."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Isso é importante por causa das pessoas envolvidas."</string>
@@ -2076,7 +2076,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desativar"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saiba mais"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"No Android 12, as notificações avançadas substituíram as notificações adaptáveis. Esse recurso mostra ações e respostas sugeridas, além de organizar suas notificações.\n\nAs notificações avançadas podem acessar o conteúdo das notificações, incluindo informações pessoais como nomes de contatos e mensagens. Elas também podem dispensar ou responder às notificações, como atender chamadas telefônicas e controlar o Não perturbe."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"No Android 12, as notificações avançadas substituíram as notificações adaptáveis. Esse recurso mostra ações e respostas sugeridas, além de organizar suas notificações.\n\nAs notificações avançadas podem acessar o conteúdo das notificações, incluindo informações pessoais como nomes de contatos e mensagens. Elas também podem dispensar ou responder às notificações, como atender ligações telefônicas e controlar o Não perturbe."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificação de informação do modo rotina"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"A bateria pode acabar antes da recarga normal"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"A Economia de bateria foi ativada para aumentar a duração da carga"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 76f8a4ece29d..029099b65e8d 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -355,8 +355,8 @@
<string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"Permite que o app remova atalhos da tela inicial sem a intervenção do usuário."</string>
<string name="permlab_processOutgoingCalls" msgid="4075056020714266558">"redirecionar as chamadas efetuadas"</string>
<string name="permdesc_processOutgoingCalls" msgid="7833149750590606334">"Permite que o app veja o número discado ao realizar uma chamada, com a opção de redirecionar a chamada para outro número ou abortá-la."</string>
- <string name="permlab_answerPhoneCalls" msgid="4131324833663725855">"atender chamadas telefônicas"</string>
- <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"Permite que o app atenda uma chamada recebida."</string>
+ <string name="permlab_answerPhoneCalls" msgid="4131324833663725855">"atender ligações telefônicas"</string>
+ <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"Permite que o app atenda uma ligação recebida."</string>
<string name="permlab_receiveSms" msgid="505961632050451881">"receber mensagens de texto (SMS)"</string>
<string name="permdesc_receiveSms" msgid="1797345626687832285">"Permite que o app receba e processe mensagens SMS. Isso significa que o app pode monitorar ou excluir mensagens enviadas para o dispositivo sem mostrá-las para você."</string>
<string name="permlab_receiveMms" msgid="4000650116674380275">"receber mensagens de texto (MMS)"</string>
@@ -420,7 +420,7 @@
<string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"Permite que o app modifique os dados sobre os contatos armazenados no dispositivo Android TV. Essa permissão autoriza os apps a excluírem dados de contato."</string>
<string name="permdesc_writeContacts" product="default" msgid="8304795696237065281">"Permite que o app modifique os dados sobre os contatos armazenados no smartphone. Essa permissão autoriza os apps a excluírem dados de contato."</string>
<string name="permlab_readCallLog" msgid="1739990210293505948">"ler registro de chamadas"</string>
- <string name="permdesc_readCallLog" msgid="8964770895425873433">"Este app pode ler seu histórico de chamadas."</string>
+ <string name="permdesc_readCallLog" msgid="8964770895425873433">"Este app pode ler seu histórico de ligações."</string>
<string name="permlab_writeCallLog" msgid="670292975137658895">"salvar no registo de chamadas"</string>
<string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"Permite que o app modifique o registro de chamadas de seu tablet, incluindo dados sobre chamadas recebidas e efetuadas. Apps maliciosos podem usar esta permissão para apagar ou modificar seu registro de chamadas."</string>
<string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"Permite que o app modifique o registro de chamadas do seu dispositivo Android TV, incluindo dados sobre chamadas recebidas e realizadas. Apps maliciosos podem usar essa permissão para apagar ou modificar seu registro de chamadas."</string>
@@ -1912,7 +1912,7 @@
<string name="call_notification_hang_up_action" msgid="9130720590159188131">"Desligar"</string>
<string name="call_notification_incoming_text" msgid="6143109825406638201">"Chamada recebida"</string>
<string name="call_notification_ongoing_text" msgid="3880832933933020875">"Chamada em andamento"</string>
- <string name="call_notification_screening_text" msgid="8396931408268940208">"Filtrando uma chamada recebida"</string>
+ <string name="call_notification_screening_text" msgid="8396931408268940208">"Filtrando uma ligação recebida"</string>
<string name="default_notification_channel_label" msgid="3697928973567217330">"Sem classificação"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Você definiu a importância dessas notificações."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Isso é importante por causa das pessoas envolvidas."</string>
@@ -2076,7 +2076,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desativar"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saiba mais"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"No Android 12, as notificações avançadas substituíram as notificações adaptáveis. Esse recurso mostra ações e respostas sugeridas, além de organizar suas notificações.\n\nAs notificações avançadas podem acessar o conteúdo das notificações, incluindo informações pessoais como nomes de contatos e mensagens. Elas também podem dispensar ou responder às notificações, como atender chamadas telefônicas e controlar o Não perturbe."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"No Android 12, as notificações avançadas substituíram as notificações adaptáveis. Esse recurso mostra ações e respostas sugeridas, além de organizar suas notificações.\n\nAs notificações avançadas podem acessar o conteúdo das notificações, incluindo informações pessoais como nomes de contatos e mensagens. Elas também podem dispensar ou responder às notificações, como atender ligações telefônicas e controlar o Não perturbe."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificação de informação do modo rotina"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"A bateria pode acabar antes da recarga normal"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"A Economia de bateria foi ativada para aumentar a duração da carga"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index b93e93a551b9..38d9d9aee8b8 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1503,7 +1503,7 @@
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"డ్రైవింగ్ యాప్ నుండి నిష్క్రమించడం కోసం నొక్కండి."</string>
<string name="back_button_label" msgid="4078224038025043387">"వెనుకకు"</string>
<string name="next_button_label" msgid="6040209156399907780">"తర్వాత"</string>
- <string name="skip_button_label" msgid="3566599811326688389">"దాటవేయి"</string>
+ <string name="skip_button_label" msgid="3566599811326688389">"స్కిప్ చేయండి"</string>
<string name="no_matches" msgid="6472699895759164599">"సరిపోలికలు లేవు"</string>
<string name="find_on_page" msgid="5400537367077438198">"పేజీలో కనుగొనండి"</string>
<string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# మ్యాచ్}other{#లో {total}}}"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3acd17143925..46abd3345335 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1872,7 +1872,7 @@
<!-- The package name of the default captive portal login app. Must be granted the
POST_NOTIFICATIONS permission.
-->
- <string name="config_defaultCaptivePortalLoginPackageName" translatable="false"></string>
+ <string name="config_defaultCaptivePortalLoginPackageName" translatable="false">com.android.captiveportallogin</string>
<!-- Whether to enable geocoder overlay which allows geocoder to be replaced
by an app at run-time. When disabled, only the
@@ -2422,7 +2422,7 @@
<!-- Whether to dismiss the active dream when an activity is started. Doesn't apply to
assistant activities (ACTIVITY_TYPE_ASSISTANT) -->
- <bool name="config_dismissDreamOnActivityStart">true</bool>
+ <bool name="config_dismissDreamOnActivityStart">false</bool>
<!-- The prefix of dream component names that are loggable. If empty, logs "other" for all. -->
<string name="config_loggable_dream_prefix" translatable="false"></string>
@@ -5176,6 +5176,15 @@
<!-- Whether displaying letterbox education is enabled for letterboxed fullscreen apps. -->
<bool name="config_letterboxIsEducationEnabled">false</bool>
+ <!-- Default min aspect ratio for unresizable apps which is used when an app doesn't specify
+ android:minAspectRatio in accordance with CDD 7.1.1.2 requirement:
+ https://source.android.com/compatibility/12/android-12-cdd#7112_screen_aspect_ratio.
+ An exception will be thrown if the given aspect ratio < 4:3. -->
+ <item name="config_letterboxDefaultMinAspectRatioForUnresizableApps" format="float" type="dimen">1.5</item>
+
+ <!-- Whether using split screen aspect ratio as a default aspect ratio for unresizable apps. -->
+ <bool name="config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled">false</bool>
+
<!-- Whether a camera compat controller is enabled to allow the user to apply or revert
treatment for stretched issues in camera viewfinder. -->
<bool name="config_isCameraCompatControlForStretchedIssuesEnabled">false</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3c03b41b8788..ad02128db613 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4395,6 +4395,8 @@
<java-symbol type="integer" name="config_letterboxDefaultPositionForHorizontalReachability" />
<java-symbol type="integer" name="config_letterboxDefaultPositionForVerticalReachability" />
<java-symbol type="bool" name="config_letterboxIsEducationEnabled" />
+ <java-symbol type="dimen" name="config_letterboxDefaultMinAspectRatioForUnresizableApps" />
+ <java-symbol type="bool" name="config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled" />
<java-symbol type="bool" name="config_isCameraCompatControlForStretchedIssuesEnabled" />
<java-symbol type="bool" name="config_hideDisplayCutoutWithDisplayArea" />
diff --git a/core/tests/coretests/src/android/colormodel/CamTest.java b/core/tests/coretests/src/android/colormodel/CamTest.java
index a70ecd720dde..5bcc5930e9a6 100644
--- a/core/tests/coretests/src/android/colormodel/CamTest.java
+++ b/core/tests/coretests/src/android/colormodel/CamTest.java
@@ -18,6 +18,9 @@ package com.android.internal.graphics.cam;
import static org.junit.Assert.assertEquals;
+import android.platform.test.annotations.LargeTest;
+
+import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -69,7 +72,7 @@ public final class CamTest {
public void camFromGreen() {
Cam cam = Cam.fromInt(GREEN);
assertEquals(79.331f, cam.getJ(), 0.001f);
- assertEquals(108.409f, cam.getChroma(), 0.001f);
+ assertEquals(108.410f, cam.getChroma(), 0.001f);
assertEquals(142.139f, cam.getHue(), 0.001f);
assertEquals(85.587f, cam.getM(), 0.001f);
assertEquals(78.604f, cam.getS(), 0.001f);
@@ -193,4 +196,32 @@ public final class CamTest {
public void deltaERedToBlue() {
assertEquals(21.415f, Cam.fromInt(RED).distance(Cam.fromInt(BLUE)), 0.001f);
}
+
+ @Test
+ public void viewingConditions_default() {
+ Frame vc = Frame.DEFAULT;
+
+ Assert.assertEquals(0.184, vc.getN(), 0.001);
+ Assert.assertEquals(29.981, vc.getAw(), 0.001);
+ Assert.assertEquals(1.016, vc.getNbb(), 0.001);
+ Assert.assertEquals(1.021, vc.getRgbD()[0], 0.001);
+ Assert.assertEquals(0.986, vc.getRgbD()[1], 0.001);
+ Assert.assertEquals(0.933, vc.getRgbD()[2], 0.001);
+ Assert.assertEquals(0.789, vc.getFlRoot(), 0.001);
+ }
+
+ @LargeTest
+ @Test
+ public void testHctReflexivity() {
+ for (int i = 0; i <= 0x00ffffff; i++) {
+ int color = 0xFF000000 | i;
+ Cam hct = Cam.fromInt(color);
+ int reconstructedFromHct = Cam.getInt(hct.getHue(), hct.getChroma(),
+ CamUtils.lstarFromInt(color));
+
+ Assert.assertEquals("input was " + Integer.toHexString(color)
+ + "; output was " + Integer.toHexString(reconstructedFromHct),
+ reconstructedFromHct, reconstructedFromHct);
+ }
+ }
}
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 05e9b3d8a0d9..f8da95d04411 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1897,12 +1897,6 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/TaskFragment.java"
},
- "-240296576": {
- "message": "handleAppTransitionReady: displayId=%d appTransition={%s} openingApps=[%s] closingApps=[%s] transit=%s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_APP_TRANSITIONS",
- "at": "com\/android\/server\/wm\/AppTransitionController.java"
- },
"-237664290": {
"message": "Pause the recording session on display %s",
"level": "VERBOSE",
@@ -2005,6 +1999,12 @@
"group": "WM_DEBUG_CONTENT_RECORDING",
"at": "com\/android\/server\/wm\/ContentRecorder.java"
},
+ "-134793542": {
+ "message": "handleAppTransitionReady: displayId=%d appTransition={%s} excludeLauncherFromAnimation=%b openingApps=[%s] closingApps=[%s] transit=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_APP_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/AppTransitionController.java"
+ },
"-134091882": {
"message": "Screenshotting Activity %s",
"level": "VERBOSE",
@@ -2521,12 +2521,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "323235828": {
- "message": "Delaying app transition for recents animation to finish",
- "level": "VERBOSE",
- "group": "WM_DEBUG_APP_TRANSITIONS",
- "at": "com\/android\/server\/wm\/AppTransitionController.java"
- },
"327461496": {
"message": "Complete pause: %s",
"level": "VERBOSE",
diff --git a/graphics/java/android/graphics/Point.java b/graphics/java/android/graphics/Point.java
index 25f76f6f6da7..2781ac4bf1da 100644
--- a/graphics/java/android/graphics/Point.java
+++ b/graphics/java/android/graphics/Point.java
@@ -36,8 +36,7 @@ public class Point implements Parcelable {
}
public Point(@NonNull Point src) {
- this.x = src.x;
- this.y = src.y;
+ set(src);
}
/**
@@ -49,6 +48,15 @@ public class Point implements Parcelable {
}
/**
+ * Sets the point's from {@code src}'s coordinates
+ * @hide
+ */
+ public void set(@NonNull Point src) {
+ this.x = src.x;
+ this.y = src.y;
+ }
+
+ /**
* Negate the point's coordinates
*/
public final void negate() {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
index 44af1a9fd780..f09a91018bf0 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
@@ -18,6 +18,8 @@ package androidx.window.extensions.embedding;
import android.annotation.NonNull;
import android.app.Activity;
+import android.util.Pair;
+import android.util.Size;
/**
* Client-side descriptor of a split that holds two containers.
@@ -66,6 +68,13 @@ class SplitContainer {
return mSplitRule;
}
+ /** Returns the minimum dimension pair of primary container and secondary container. */
+ @NonNull
+ Pair<Size, Size> getMinDimensionsPair() {
+ return new Pair<>(mPrimaryContainer.getMinDimensions(),
+ mSecondaryContainer.getMinDimensions());
+ }
+
boolean isPlaceholderContainer() {
return (mSplitRule instanceof SplitPlaceholderRule);
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 575c3f002791..242e9ab6beee 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -24,9 +24,11 @@ import static androidx.window.extensions.embedding.SplitContainer.getFinishSecon
import static androidx.window.extensions.embedding.SplitContainer.isStickyPlaceholderRule;
import static androidx.window.extensions.embedding.SplitContainer.shouldFinishAssociatedContainerWhenAdjacent;
import static androidx.window.extensions.embedding.SplitContainer.shouldFinishAssociatedContainerWhenStacked;
+import static androidx.window.extensions.embedding.SplitPresenter.boundsSmallerThanMinDimensions;
+import static androidx.window.extensions.embedding.SplitPresenter.getActivityIntentMinDimensionsPair;
+import static androidx.window.extensions.embedding.SplitPresenter.getMinDimensions;
+import static androidx.window.extensions.embedding.SplitPresenter.shouldShowSideBySide;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityClient;
import android.app.ActivityOptions;
@@ -43,11 +45,15 @@ import android.os.IBinder;
import android.os.Looper;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Pair;
+import android.util.Size;
import android.util.SparseArray;
import android.window.TaskFragmentInfo;
import android.window.WindowContainerTransaction;
import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.window.common.EmptyLifecycleCallbacksAdapter;
import com.android.internal.annotations.VisibleForTesting;
@@ -63,7 +69,7 @@ import java.util.function.Consumer;
*/
public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmentCallback,
ActivityEmbeddingComponent {
- private static final String TAG = "SplitController";
+ static final String TAG = "SplitController";
@VisibleForTesting
@GuardedBy("mLock")
@@ -350,7 +356,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
if (!(rule instanceof SplitRule)) {
continue;
}
- if (mPresenter.shouldShowSideBySide(taskContainer.getTaskBounds(), (SplitRule) rule)) {
+ if (shouldShowSideBySide(taskContainer.getTaskBounds(), (SplitRule) rule)) {
return true;
}
}
@@ -610,11 +616,15 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
primaryActivity);
final SplitContainer splitContainer = getActiveSplitForContainer(primaryContainer);
if (splitContainer != null && primaryContainer == splitContainer.getPrimaryContainer()
- && canReuseContainer(splitRule, splitContainer.getSplitRule())) {
+ && canReuseContainer(splitRule, splitContainer.getSplitRule())
+ && !boundsSmallerThanMinDimensions(primaryContainer.getLastRequestedBounds(),
+ getMinDimensions(primaryActivity))) {
// Can launch in the existing secondary container if the rules share the same
// presentation.
final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer();
- if (secondaryContainer == getContainerWithActivity(secondaryActivity)) {
+ if (secondaryContainer == getContainerWithActivity(secondaryActivity)
+ && !boundsSmallerThanMinDimensions(secondaryContainer.getLastRequestedBounds(),
+ getMinDimensions(secondaryActivity))) {
// The activity is already in the target TaskFragment.
return true;
}
@@ -791,9 +801,15 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
&& (canReuseContainer(splitRule, splitContainer.getSplitRule())
// TODO(b/231845476) we should always respect clearTop.
|| !respectClearTop)) {
- // Can launch in the existing secondary container if the rules share the same
- // presentation.
- return splitContainer.getSecondaryContainer();
+ final Rect secondaryBounds = splitContainer.getSecondaryContainer()
+ .getLastRequestedBounds();
+ if (secondaryBounds.isEmpty()
+ || !boundsSmallerThanMinDimensions(secondaryBounds,
+ getMinDimensions(intent))) {
+ // Can launch in the existing secondary container if the rules share the same
+ // presentation.
+ return splitContainer.getSecondaryContainer();
+ }
}
// Create a new TaskFragment to split with the primary activity for the new activity.
return mPresenter.createNewSplitWithEmptySideContainer(wct, primaryActivity, intent,
@@ -1117,8 +1133,16 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
// Check if there is enough space for launch
final SplitPlaceholderRule placeholderRule = getPlaceholderRule(activity);
- if (placeholderRule == null || !mPresenter.shouldShowSideBySide(
- mPresenter.getParentContainerBounds(activity), placeholderRule)) {
+
+ if (placeholderRule == null) {
+ return false;
+ }
+
+ final Pair<Size, Size> minDimensionsPair = getActivityIntentMinDimensionsPair(activity,
+ placeholderRule.getPlaceholderIntent());
+ if (!shouldShowSideBySide(
+ mPresenter.getParentContainerBounds(activity), placeholderRule,
+ minDimensionsPair)) {
return false;
}
@@ -1161,7 +1185,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return false;
}
- if (mPresenter.shouldShowSideBySide(splitContainer)) {
+ if (shouldShowSideBySide(splitContainer)) {
return false;
}
@@ -1233,7 +1257,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
// Splits that are not showing side-by-side are reported as having 0 split
// ratio, since by definition in the API the primary container occupies no
// width of the split when covered by the secondary.
- mPresenter.shouldShowSideBySide(container)
+ shouldShowSideBySide(container)
? container.getSplitRule().getSplitRatio()
: 0.0f);
splitStates.add(splitState);
@@ -1402,7 +1426,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
// Decide whether the associated container should be retained based on the current
// presentation mode.
- if (mPresenter.shouldShowSideBySide(splitContainer)) {
+ if (shouldShowSideBySide(splitContainer)) {
return !shouldFinishAssociatedContainerWhenAdjacent(finishBehavior);
} else {
return !shouldFinishAssociatedContainerWhenStacked(finishBehavior);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index ac3b05a0e825..1b79ad999435 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -16,15 +16,23 @@
package androidx.window.extensions.embedding;
+import static android.content.pm.PackageManager.MATCH_ALL;
+
import android.app.Activity;
+import android.app.ActivityThread;
import android.app.WindowConfiguration;
import android.app.WindowConfiguration.WindowingMode;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
import android.util.LayoutDirection;
+import android.util.Pair;
+import android.util.Size;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowMetrics;
@@ -34,6 +42,8 @@ import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.concurrent.Executor;
/**
@@ -41,9 +51,12 @@ import java.util.concurrent.Executor;
* {@link SplitController}.
*/
class SplitPresenter extends JetpackTaskFragmentOrganizer {
- private static final int POSITION_START = 0;
- private static final int POSITION_END = 1;
- private static final int POSITION_FILL = 2;
+ @VisibleForTesting
+ static final int POSITION_START = 0;
+ @VisibleForTesting
+ static final int POSITION_END = 1;
+ @VisibleForTesting
+ static final int POSITION_FILL = 2;
@IntDef(value = {
POSITION_START,
@@ -103,8 +116,10 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
@NonNull WindowContainerTransaction wct, @NonNull Activity primaryActivity,
@NonNull Intent secondaryIntent, @NonNull SplitPairRule rule) {
final Rect parentBounds = getParentContainerBounds(primaryActivity);
+ final Pair<Size, Size> minDimensionsPair = getActivityIntentMinDimensionsPair(
+ primaryActivity, secondaryIntent);
final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, parentBounds, rule,
- isLtr(primaryActivity, rule));
+ primaryActivity, minDimensionsPair);
final TaskFragmentContainer primaryContainer = prepareContainerForActivity(wct,
primaryActivity, primaryRectBounds, null);
@@ -113,7 +128,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
final TaskFragmentContainer secondaryContainer = mController.newContainer(
secondaryIntent, primaryActivity, taskId);
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds,
- rule, isLtr(primaryActivity, rule));
+ rule, primaryActivity, minDimensionsPair);
final int windowingMode = mController.getTaskContainer(taskId)
.getWindowingModeForSplitTaskFragment(secondaryRectBounds);
createTaskFragment(wct, secondaryContainer.getTaskFragmentToken(),
@@ -121,7 +136,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
windowingMode);
// Set adjacent to each other so that the containers below will be invisible.
- setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule);
+ setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule,
+ minDimensionsPair);
mController.registerSplit(wct, primaryContainer, primaryActivity, secondaryContainer, rule);
@@ -144,13 +160,15 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
final WindowContainerTransaction wct = new WindowContainerTransaction();
final Rect parentBounds = getParentContainerBounds(primaryActivity);
+ final Pair<Size, Size> minDimensionsPair = getActivitiesMinDimensionsPair(primaryActivity,
+ secondaryActivity);
final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, parentBounds, rule,
- isLtr(primaryActivity, rule));
+ primaryActivity, minDimensionsPair);
final TaskFragmentContainer primaryContainer = prepareContainerForActivity(wct,
primaryActivity, primaryRectBounds, null);
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds, rule,
- isLtr(primaryActivity, rule));
+ primaryActivity, minDimensionsPair);
final TaskFragmentContainer curSecondaryContainer = mController.getContainerWithActivity(
secondaryActivity);
TaskFragmentContainer containerToAvoid = primaryContainer;
@@ -162,7 +180,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
secondaryActivity, secondaryRectBounds, containerToAvoid);
// Set adjacent to each other so that the containers below will be invisible.
- setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule);
+ setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule,
+ minDimensionsPair);
mController.registerSplit(wct, primaryContainer, primaryActivity, secondaryContainer, rule);
@@ -211,10 +230,12 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent activityIntent,
@Nullable Bundle activityOptions, @NonNull SplitRule rule, boolean isPlaceholder) {
final Rect parentBounds = getParentContainerBounds(launchingActivity);
+ final Pair<Size, Size> minDimensionsPair = getActivityIntentMinDimensionsPair(
+ launchingActivity, activityIntent);
final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, parentBounds, rule,
- isLtr(launchingActivity, rule));
+ launchingActivity, minDimensionsPair);
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds, rule,
- isLtr(launchingActivity, rule));
+ launchingActivity, minDimensionsPair);
TaskFragmentContainer primaryContainer = mController.getContainerWithActivity(
launchingActivity);
@@ -258,11 +279,11 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
if (activity == null) {
return;
}
- final boolean isLtr = isLtr(activity, rule);
+ final Pair<Size, Size> minDimensionsPair = splitContainer.getMinDimensionsPair();
final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, parentBounds, rule,
- isLtr);
+ activity, minDimensionsPair);
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds, rule,
- isLtr);
+ activity, minDimensionsPair);
final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer();
// Whether the placeholder is becoming side-by-side with the primary from fullscreen.
final boolean isPlaceholderBecomingSplit = splitContainer.isPlaceholderContainer()
@@ -273,7 +294,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
// are created again.
resizeTaskFragmentIfRegistered(wct, primaryContainer, primaryRectBounds);
resizeTaskFragmentIfRegistered(wct, secondaryContainer, secondaryRectBounds);
- setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule);
+ setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule,
+ minDimensionsPair);
if (isPlaceholderBecomingSplit) {
// When placeholder is shown in split, we should keep the focus on the primary.
wct.requestFocusOnTaskFragment(primaryContainer.getTaskFragmentToken());
@@ -287,11 +309,12 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
private void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct,
@NonNull TaskFragmentContainer primaryContainer,
- @NonNull TaskFragmentContainer secondaryContainer, @NonNull SplitRule splitRule) {
+ @NonNull TaskFragmentContainer secondaryContainer, @NonNull SplitRule splitRule,
+ @NonNull Pair<Size, Size> minDimensionsPair) {
final Rect parentBounds = getParentContainerBounds(primaryContainer);
// Clear adjacent TaskFragments if the container is shown in fullscreen, or the
// secondaryContainer could not be finished.
- if (!shouldShowSideBySide(parentBounds, splitRule)) {
+ if (!shouldShowSideBySide(parentBounds, splitRule, minDimensionsPair)) {
setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(),
null /* secondary */, null /* splitRule */);
} else {
@@ -373,41 +396,132 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
super.updateWindowingMode(wct, fragmentToken, windowingMode);
}
- boolean shouldShowSideBySide(@NonNull SplitContainer splitContainer) {
+ static boolean shouldShowSideBySide(@NonNull Rect parentBounds, @NonNull SplitRule rule) {
+ return shouldShowSideBySide(parentBounds, rule, null /* minimumDimensionPair */);
+ }
+
+ static boolean shouldShowSideBySide(@NonNull SplitContainer splitContainer) {
final Rect parentBounds = getParentContainerBounds(splitContainer.getPrimaryContainer());
- return shouldShowSideBySide(parentBounds, splitContainer.getSplitRule());
+
+ return shouldShowSideBySide(parentBounds, splitContainer.getSplitRule(),
+ splitContainer.getMinDimensionsPair());
}
- boolean shouldShowSideBySide(@Nullable Rect parentBounds, @NonNull SplitRule rule) {
+ static boolean shouldShowSideBySide(@NonNull Rect parentBounds, @NonNull SplitRule rule,
+ @Nullable Pair<Size, Size> minDimensionsPair) {
// TODO(b/190433398): Supply correct insets.
final WindowMetrics parentMetrics = new WindowMetrics(parentBounds,
new WindowInsets(new Rect()));
- return rule.checkParentMetrics(parentMetrics);
+ // Don't show side by side if bounds is not qualified.
+ if (!rule.checkParentMetrics(parentMetrics)) {
+ return false;
+ }
+ final float splitRatio = rule.getSplitRatio();
+ // We only care the size of the bounds regardless of its position.
+ final Rect primaryBounds = getPrimaryBounds(parentBounds, splitRatio, true /* isLtr */);
+ final Rect secondaryBounds = getSecondaryBounds(parentBounds, splitRatio, true /* isLtr */);
+
+ if (minDimensionsPair == null) {
+ return true;
+ }
+ return !boundsSmallerThanMinDimensions(primaryBounds, minDimensionsPair.first)
+ && !boundsSmallerThanMinDimensions(secondaryBounds, minDimensionsPair.second);
}
@NonNull
- private Rect getBoundsForPosition(@Position int position, @NonNull Rect parentBounds,
- @NonNull SplitRule rule, boolean isLtr) {
- if (!shouldShowSideBySide(parentBounds, rule)) {
- return new Rect();
+ static Pair<Size, Size> getActivitiesMinDimensionsPair(Activity primaryActivity,
+ Activity secondaryActivity) {
+ return new Pair<>(getMinDimensions(primaryActivity), getMinDimensions(secondaryActivity));
+ }
+
+ @NonNull
+ static Pair<Size, Size> getActivityIntentMinDimensionsPair(Activity primaryActivity,
+ Intent secondaryIntent) {
+ return new Pair<>(getMinDimensions(primaryActivity), getMinDimensions(secondaryIntent));
+ }
+
+ @Nullable
+ static Size getMinDimensions(@Nullable Activity activity) {
+ if (activity == null) {
+ return null;
+ }
+ final ActivityInfo.WindowLayout windowLayout = activity.getActivityInfo().windowLayout;
+ if (windowLayout == null) {
+ return null;
}
+ return new Size(windowLayout.minWidth, windowLayout.minHeight);
+ }
+ // TODO(b/232871351): find a light-weight approach for this check.
+ @Nullable
+ static Size getMinDimensions(@Nullable Intent intent) {
+ if (intent == null) {
+ return null;
+ }
+ final PackageManager packageManager = ActivityThread.currentActivityThread()
+ .getApplication().getPackageManager();
+ final ResolveInfo resolveInfo = packageManager.resolveActivity(intent,
+ PackageManager.ResolveInfoFlags.of(MATCH_ALL));
+ if (resolveInfo == null) {
+ return null;
+ }
+ final ActivityInfo activityInfo = resolveInfo.activityInfo;
+ if (activityInfo == null) {
+ return null;
+ }
+ final ActivityInfo.WindowLayout windowLayout = activityInfo.windowLayout;
+ if (windowLayout == null) {
+ return null;
+ }
+ return new Size(windowLayout.minWidth, windowLayout.minHeight);
+ }
+
+ static boolean boundsSmallerThanMinDimensions(@NonNull Rect bounds,
+ @Nullable Size minDimensions) {
+ if (minDimensions == null) {
+ return false;
+ }
+ return bounds.width() < minDimensions.getWidth()
+ || bounds.height() < minDimensions.getHeight();
+ }
+
+ @VisibleForTesting
+ @NonNull
+ static Rect getBoundsForPosition(@Position int position, @NonNull Rect parentBounds,
+ @NonNull SplitRule rule, @NonNull Activity primaryActivity,
+ @Nullable Pair<Size, Size> minDimensionsPair) {
+ if (!shouldShowSideBySide(parentBounds, rule, minDimensionsPair)) {
+ return new Rect();
+ }
+ final boolean isLtr = isLtr(primaryActivity, rule);
final float splitRatio = rule.getSplitRatio();
- final float rtlSplitRatio = 1 - splitRatio;
+
switch (position) {
case POSITION_START:
- return isLtr ? getLeftContainerBounds(parentBounds, splitRatio)
- : getRightContainerBounds(parentBounds, rtlSplitRatio);
+ return getPrimaryBounds(parentBounds, splitRatio, isLtr);
case POSITION_END:
- return isLtr ? getRightContainerBounds(parentBounds, splitRatio)
- : getLeftContainerBounds(parentBounds, rtlSplitRatio);
+ return getSecondaryBounds(parentBounds, splitRatio, isLtr);
case POSITION_FILL:
- return parentBounds;
+ default:
+ return new Rect();
}
- return parentBounds;
}
- private Rect getLeftContainerBounds(@NonNull Rect parentBounds, float splitRatio) {
+ @NonNull
+ private static Rect getPrimaryBounds(@NonNull Rect parentBounds, float splitRatio,
+ boolean isLtr) {
+ return isLtr ? getLeftContainerBounds(parentBounds, splitRatio)
+ : getRightContainerBounds(parentBounds, 1 - splitRatio);
+ }
+
+ @NonNull
+ private static Rect getSecondaryBounds(@NonNull Rect parentBounds, float splitRatio,
+ boolean isLtr) {
+ return isLtr ? getRightContainerBounds(parentBounds, splitRatio)
+ : getLeftContainerBounds(parentBounds, 1 - splitRatio);
+ }
+
+ private static Rect getLeftContainerBounds(@NonNull Rect parentBounds, float splitRatio) {
return new Rect(
parentBounds.left,
parentBounds.top,
@@ -415,7 +529,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
parentBounds.bottom);
}
- private Rect getRightContainerBounds(@NonNull Rect parentBounds, float splitRatio) {
+ private static Rect getRightContainerBounds(@NonNull Rect parentBounds, float splitRatio) {
return new Rect(
(int) (parentBounds.left + parentBounds.width() * splitRatio),
parentBounds.top,
@@ -427,7 +541,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
* Checks if a split with the provided rule should be displays in left-to-right layout
* direction, either always or with the current configuration.
*/
- private boolean isLtr(@NonNull Context context, @NonNull SplitRule rule) {
+ private static boolean isLtr(@NonNull Context context, @NonNull SplitRule rule) {
switch (rule.getLayoutDirection()) {
case LayoutDirection.LOCALE:
return context.getResources().getConfiguration().getLayoutDirection()
@@ -441,7 +555,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
}
@NonNull
- Rect getParentContainerBounds(@NonNull TaskFragmentContainer container) {
+ static Rect getParentContainerBounds(@NonNull TaskFragmentContainer container) {
return container.getTaskContainer().getTaskBounds();
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 497c2478806e..abf32a26efa2 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -26,6 +26,7 @@ import android.content.Intent;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
+import android.util.Size;
import android.window.TaskFragmentInfo;
import android.window.WindowContainerTransaction;
@@ -280,6 +281,9 @@ class TaskFragmentContainer {
* Adds a container that should be finished when this container is finished.
*/
void addContainerToFinishOnExit(@NonNull TaskFragmentContainer containerToFinish) {
+ if (mIsFinished) {
+ return;
+ }
mContainersToFinishOnExit.add(containerToFinish);
}
@@ -287,6 +291,9 @@ class TaskFragmentContainer {
* Removes a container that should be finished when this container is finished.
*/
void removeContainerToFinishOnExit(@NonNull TaskFragmentContainer containerToRemove) {
+ if (mIsFinished) {
+ return;
+ }
mContainersToFinishOnExit.remove(containerToRemove);
}
@@ -294,6 +301,9 @@ class TaskFragmentContainer {
* Adds an activity that should be finished when this container is finished.
*/
void addActivityToFinishOnExit(@NonNull Activity activityToFinish) {
+ if (mIsFinished) {
+ return;
+ }
mActivitiesToFinishOnExit.add(activityToFinish);
}
@@ -301,11 +311,17 @@ class TaskFragmentContainer {
* Removes an activity that should be finished when this container is finished.
*/
void removeActivityToFinishOnExit(@NonNull Activity activityToRemove) {
+ if (mIsFinished) {
+ return;
+ }
mActivitiesToFinishOnExit.remove(activityToRemove);
}
/** Removes all dependencies that should be finished when this container is finished. */
void resetDependencies() {
+ if (mIsFinished) {
+ return;
+ }
mContainersToFinishOnExit.clear();
mActivitiesToFinishOnExit.clear();
}
@@ -399,6 +415,11 @@ class TaskFragmentContainer {
}
}
+ @NonNull
+ Rect getLastRequestedBounds() {
+ return mLastRequestedBounds;
+ }
+
/**
* Checks if last requested windowing mode is equal to the provided value.
*/
@@ -424,6 +445,31 @@ class TaskFragmentContainer {
return mTaskContainer;
}
+ @Nullable
+ Size getMinDimensions() {
+ if (mInfo == null) {
+ return null;
+ }
+ int maxMinWidth = mInfo.getMinimumWidth();
+ int maxMinHeight = mInfo.getMinimumHeight();
+ for (Activity activity : mPendingAppearedActivities) {
+ final Size minDimensions = SplitPresenter.getMinDimensions(activity);
+ if (minDimensions == null) {
+ continue;
+ }
+ maxMinWidth = Math.max(maxMinWidth, minDimensions.getWidth());
+ maxMinHeight = Math.max(maxMinHeight, minDimensions.getHeight());
+ }
+ if (mPendingAppearedIntent != null) {
+ final Size minDimensions = SplitPresenter.getMinDimensions(mPendingAppearedIntent);
+ if (minDimensions != null) {
+ maxMinWidth = Math.max(maxMinWidth, minDimensions.getWidth());
+ maxMinHeight = Math.max(maxMinHeight, minDimensions.getHeight());
+ }
+ }
+ return new Size(maxMinWidth, maxMinHeight);
+ }
+
@Override
public String toString() {
return toString(true /* includeContainersToFinishOnExit */);
diff --git a/libs/WindowManager/Jetpack/tests/unittest/AndroidManifest.xml b/libs/WindowManager/Jetpack/tests/unittest/AndroidManifest.xml
index b12b6f6f0ef1..c736e9ed971e 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/AndroidManifest.xml
+++ b/libs/WindowManager/Jetpack/tests/unittest/AndroidManifest.xml
@@ -22,6 +22,11 @@
<application android:debuggable="true" android:largeHeap="true">
<uses-library android:name="android.test.mock" />
<uses-library android:name="android.test.runner" />
+
+ <activity android:name="androidx.window.extensions.embedding.MinimumDimensionActivity">
+ <layout android:minWidth="600px"
+ android:minHeight="1200px"/>
+ </activity>
</application>
<instrumentation
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java
new file mode 100644
index 000000000000..835c40365cda
--- /dev/null
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.embedding;
+
+import static androidx.window.extensions.embedding.SplitRule.FINISH_ALWAYS;
+import static androidx.window.extensions.embedding.SplitRule.FINISH_NEVER;
+
+import static org.mockito.Mockito.mock;
+
+import android.annotation.NonNull;
+import android.app.Activity;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.util.Pair;
+import android.window.TaskFragmentInfo;
+import android.window.WindowContainerToken;
+
+import java.util.Collections;
+
+public class EmbeddingTestUtils {
+ static final Rect TASK_BOUNDS = new Rect(0, 0, 600, 1200);
+ static final int TASK_ID = 10;
+ static final float SPLIT_RATIO = 0.5f;
+ /** Default finish behavior in Jetpack. */
+ static final int DEFAULT_FINISH_PRIMARY_WITH_SECONDARY = FINISH_NEVER;
+ static final int DEFAULT_FINISH_SECONDARY_WITH_PRIMARY = FINISH_ALWAYS;
+
+ private EmbeddingTestUtils() {}
+
+ /** Gets the bounds of a TaskFragment that is in split. */
+ static Rect getSplitBounds(boolean isPrimary) {
+ final int width = (int) (TASK_BOUNDS.width() * SPLIT_RATIO);
+ return isPrimary
+ ? new Rect(TASK_BOUNDS.left, TASK_BOUNDS.top, TASK_BOUNDS.left + width,
+ TASK_BOUNDS.bottom)
+ : new Rect(
+ TASK_BOUNDS.left + width, TASK_BOUNDS.top, TASK_BOUNDS.right,
+ TASK_BOUNDS.bottom);
+ }
+
+ /** Creates a rule to always split the given activity and the given intent. */
+ static SplitRule createSplitRule(@NonNull Activity primaryActivity,
+ @NonNull Intent secondaryIntent) {
+ final Pair<Activity, Intent> targetPair = new Pair<>(primaryActivity, secondaryIntent);
+ return new SplitPairRule.Builder(
+ activityPair -> false,
+ targetPair::equals,
+ w -> true)
+ .setSplitRatio(SPLIT_RATIO)
+ .setShouldClearTop(true)
+ .build();
+ }
+
+ /** Creates a rule to always split the given activities. */
+ static SplitRule createSplitRule(@NonNull Activity primaryActivity,
+ @NonNull Activity secondaryActivity) {
+ return createSplitRule(primaryActivity, secondaryActivity,
+ DEFAULT_FINISH_PRIMARY_WITH_SECONDARY, DEFAULT_FINISH_SECONDARY_WITH_PRIMARY,
+ true /* clearTop */);
+ }
+
+ /** Creates a rule to always split the given activities with the given finish behaviors. */
+ static SplitRule createSplitRule(@NonNull Activity primaryActivity,
+ @NonNull Activity secondaryActivity, int finishPrimaryWithSecondary,
+ int finishSecondaryWithPrimary, boolean clearTop) {
+ final Pair<Activity, Activity> targetPair = new Pair<>(primaryActivity, secondaryActivity);
+ return new SplitPairRule.Builder(
+ targetPair::equals,
+ activityIntentPair -> false,
+ w -> true)
+ .setSplitRatio(SPLIT_RATIO)
+ .setFinishPrimaryWithSecondary(finishPrimaryWithSecondary)
+ .setFinishSecondaryWithPrimary(finishSecondaryWithPrimary)
+ .setShouldClearTop(clearTop)
+ .build();
+ }
+
+ /** Creates a mock TaskFragmentInfo for the given TaskFragment. */
+ static TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container,
+ @NonNull Activity activity) {
+ return new TaskFragmentInfo(container.getTaskFragmentToken(),
+ mock(WindowContainerToken.class),
+ new Configuration(),
+ 1,
+ true /* isVisible */,
+ Collections.singletonList(activity.getActivityToken()),
+ new Point(),
+ false /* isTaskClearedForReuse */,
+ false /* isTaskFragmentClearedForPip */,
+ new Point());
+ }
+}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
index a191e685f651..4d2595275f20 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
@@ -18,6 +18,8 @@ package androidx.window.extensions.embedding;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -58,8 +60,6 @@ import java.util.ArrayList;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class JetpackTaskFragmentOrganizerTest {
- private static final int TASK_ID = 10;
-
@Mock
private WindowContainerTransaction mTransaction;
@Mock
@@ -131,6 +131,7 @@ public class JetpackTaskFragmentOrganizerTest {
return new TaskFragmentInfo(container.getTaskFragmentToken(),
mock(WindowContainerToken.class), new Configuration(), 0 /* runningActivityCount */,
false /* isVisible */, new ArrayList<>(), new Point(),
- false /* isTaskClearedForReuse */, false /* isTaskFragmentClearedForPip */);
+ false /* isTaskClearedForReuse */, false /* isTaskFragmentClearedForPip */,
+ new Point());
}
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/MinimumDimensionActivity.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/MinimumDimensionActivity.java
new file mode 100644
index 000000000000..ffcaf3e6f546
--- /dev/null
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/MinimumDimensionActivity.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.embedding;
+
+import android.app.Activity;
+
+/**
+ * Activity that declares minWidth and minHeight in
+ * {@link android.content.pm.ActivityInfo.WindowLayout}
+ */
+public class MinimumDimensionActivity extends Activity {}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 937d670287ad..ef7728cec387 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -19,6 +19,14 @@ package androidx.window.extensions.embedding;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.SPLIT_RATIO;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_BOUNDS;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.createMockTaskFragmentInfo;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitRule;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.getSplitBounds;
+import static androidx.window.extensions.embedding.SplitRule.FINISH_ALWAYS;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -46,20 +54,19 @@ import android.app.Activity;
import android.app.ActivityOptions;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
-import android.util.Pair;
import android.window.TaskFragmentInfo;
-import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
+import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -83,9 +90,6 @@ import java.util.List;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SplitControllerTest {
- private static final int TASK_ID = 10;
- private static final Rect TASK_BOUNDS = new Rect(0, 0, 600, 1200);
- private static final float SPLIT_RATIO = 0.5f;
private static final Intent PLACEHOLDER_INTENT = new Intent().setComponent(
new ComponentName("test", "placeholder"));
@@ -413,6 +417,25 @@ public class SplitControllerTest {
}
@Test
+ public void testResolveStartActivityIntent_shouldLaunchInFullscreen() {
+ final Intent intent = new Intent().setComponent(
+ new ComponentName(ApplicationProvider.getApplicationContext(),
+ MinimumDimensionActivity.class));
+ setupSplitRule(mActivity, intent);
+ final Activity primaryActivity = createMockActivity();
+ addSplitTaskFragments(primaryActivity, mActivity);
+
+ final TaskFragmentContainer container = mSplitController.resolveStartActivityIntent(
+ mTransaction, TASK_ID, intent, null /* launchingActivity */);
+ final TaskFragmentContainer primaryContainer = mSplitController.getContainerWithActivity(
+ mActivity);
+
+ assertNotNull(mSplitController.getActiveSplitForContainers(primaryContainer, container));
+ assertTrue(primaryContainer.areLastRequestedBoundsEqual(null));
+ assertTrue(container.areLastRequestedBoundsEqual(null));
+ }
+
+ @Test
public void testPlaceActivityInTopContainer() {
mSplitController.placeActivityInTopContainer(mActivity);
@@ -760,6 +783,52 @@ public class SplitControllerTest {
}
@Test
+ public void testResolveActivityToContainer_primaryActivityMinDimensionsNotSatisfied() {
+ final Activity activityBelow = createMockActivity();
+ setupSplitRule(mActivity, activityBelow);
+
+ ActivityInfo aInfo = new ActivityInfo();
+ final Rect primaryBounds = getSplitBounds(true /* isPrimary */);
+ aInfo.windowLayout = new ActivityInfo.WindowLayout(0, 0, 0, 0, 0,
+ primaryBounds.width() + 1, primaryBounds.height() + 1);
+ doReturn(aInfo).when(mActivity).getActivityInfo();
+
+ final TaskFragmentContainer container = mSplitController.newContainer(activityBelow,
+ TASK_ID);
+ container.addPendingAppearedActivity(mActivity);
+
+ // Allow to split as primary.
+ boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ true /* isOnReparent */);
+
+ assertTrue(result);
+ assertSplitPair(mActivity, activityBelow, true /* matchParentBounds */);
+ }
+
+ @Test
+ public void testResolveActivityToContainer_secondaryActivityMinDimensionsNotSatisfied() {
+ final Activity activityBelow = createMockActivity();
+ setupSplitRule(activityBelow, mActivity);
+
+ ActivityInfo aInfo = new ActivityInfo();
+ final Rect secondaryBounds = getSplitBounds(false /* isPrimary */);
+ aInfo.windowLayout = new ActivityInfo.WindowLayout(0, 0, 0, 0, 0,
+ secondaryBounds.width() + 1, secondaryBounds.height() + 1);
+ doReturn(aInfo).when(mActivity).getActivityInfo();
+
+ final TaskFragmentContainer container = mSplitController.newContainer(activityBelow,
+ TASK_ID);
+ container.addPendingAppearedActivity(mActivity);
+
+ // Allow to split as primary.
+ boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* isOnReparent */);
+
+ assertTrue(result);
+ assertSplitPair(activityBelow, mActivity, true /* matchParentBounds */);
+ }
+
+ @Test
public void testResolveActivityToContainer_inUnknownTaskFragment() {
doReturn(new Binder()).when(mSplitController).getInitialTaskFragmentToken(mActivity);
@@ -788,6 +857,38 @@ public class SplitControllerTest {
assertTrue(activityOptions.getAvoidMoveToFront());
}
+ @Test
+ public void testFinishTwoSplitThatShouldFinishTogether() {
+ // Setup two split pairs that should finish each other when finishing one.
+ final Activity secondaryActivity0 = createMockActivity();
+ final Activity secondaryActivity1 = createMockActivity();
+ final TaskFragmentContainer primaryContainer = createMockTaskFragmentContainer(mActivity);
+ final TaskFragmentContainer secondaryContainer0 = createMockTaskFragmentContainer(
+ secondaryActivity0);
+ final TaskFragmentContainer secondaryContainer1 = createMockTaskFragmentContainer(
+ secondaryActivity1);
+ final TaskContainer taskContainer = mSplitController.getTaskContainer(TASK_ID);
+ final SplitRule rule0 = createSplitRule(mActivity, secondaryActivity0, FINISH_ALWAYS,
+ FINISH_ALWAYS, false /* clearTop */);
+ final SplitRule rule1 = createSplitRule(mActivity, secondaryActivity1, FINISH_ALWAYS,
+ FINISH_ALWAYS, false /* clearTop */);
+ registerSplitPair(primaryContainer, secondaryContainer0, rule0);
+ registerSplitPair(primaryContainer, secondaryContainer1, rule1);
+
+ primaryContainer.finish(true /* shouldFinishDependent */, mSplitPresenter,
+ mTransaction, mSplitController);
+
+ // All containers and activities should be finished based on the FINISH_ALWAYS behavior.
+ assertTrue(primaryContainer.isFinished());
+ assertTrue(secondaryContainer0.isFinished());
+ assertTrue(secondaryContainer1.isFinished());
+ verify(mActivity).finish();
+ verify(secondaryActivity0).finish();
+ verify(secondaryActivity1).finish();
+ assertTrue(taskContainer.mContainers.isEmpty());
+ assertTrue(taskContainer.mSplitContainers.isEmpty());
+ }
+
/** Creates a mock activity in the organizer process. */
private Activity createMockActivity() {
final Activity activity = mock(Activity.class);
@@ -796,23 +897,10 @@ public class SplitControllerTest {
doReturn(activityToken).when(activity).getActivityToken();
doReturn(activity).when(mSplitController).getActivity(activityToken);
doReturn(TASK_ID).when(activity).getTaskId();
+ doReturn(new ActivityInfo()).when(activity).getActivityInfo();
return activity;
}
- /** Creates a mock TaskFragmentInfo for the given TaskFragment. */
- private TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container,
- @NonNull Activity activity) {
- return new TaskFragmentInfo(container.getTaskFragmentToken(),
- mock(WindowContainerToken.class),
- new Configuration(),
- 1,
- true /* isVisible */,
- Collections.singletonList(activity.getActivityToken()),
- new Point(),
- false /* isTaskClearedForReuse */,
- false /* isTaskFragmentClearedForPip */);
- }
-
/** Creates a mock TaskFragment that has been registered and appeared in the organizer. */
private TaskFragmentContainer createMockTaskFragmentContainer(@NonNull Activity activity) {
final TaskFragmentContainer container = mSplitController.newContainer(activity, TASK_ID);
@@ -867,45 +955,23 @@ public class SplitControllerTest {
mSplitController.setEmbeddingRules(Collections.singleton(splitRule));
}
- /** Creates a rule to always split the given activity and the given intent. */
- private SplitRule createSplitRule(@NonNull Activity primaryActivity,
- @NonNull Intent secondaryIntent) {
- final Pair<Activity, Intent> targetPair = new Pair<>(primaryActivity, secondaryIntent);
- return new SplitPairRule.Builder(
- activityPair -> false,
- targetPair::equals,
- w -> true)
- .setSplitRatio(SPLIT_RATIO)
- .setShouldClearTop(true)
- .build();
- }
-
- /** Creates a rule to always split the given activities. */
- private SplitRule createSplitRule(@NonNull Activity primaryActivity,
- @NonNull Activity secondaryActivity) {
- final Pair<Activity, Activity> targetPair = new Pair<>(primaryActivity, secondaryActivity);
- return new SplitPairRule.Builder(
- targetPair::equals,
- activityIntentPair -> false,
- w -> true)
- .setSplitRatio(SPLIT_RATIO)
- .setShouldClearTop(true)
- .build();
- }
-
/** Adds a pair of TaskFragments as split for the given activities. */
private void addSplitTaskFragments(@NonNull Activity primaryActivity,
@NonNull Activity secondaryActivity) {
- final TaskFragmentContainer primaryContainer = createMockTaskFragmentContainer(
- primaryActivity);
- final TaskFragmentContainer secondaryContainer = createMockTaskFragmentContainer(
- secondaryActivity);
+ registerSplitPair(createMockTaskFragmentContainer(primaryActivity),
+ createMockTaskFragmentContainer(secondaryActivity),
+ createSplitRule(primaryActivity, secondaryActivity));
+ }
+
+ /** Registers the two given TaskFragments as split pair. */
+ private void registerSplitPair(@NonNull TaskFragmentContainer primaryContainer,
+ @NonNull TaskFragmentContainer secondaryContainer, @NonNull SplitRule rule) {
mSplitController.registerSplit(
mock(WindowContainerTransaction.class),
primaryContainer,
- primaryActivity,
+ primaryContainer.getTopNonFinishingActivity(),
secondaryContainer,
- createSplitRule(primaryActivity, secondaryActivity));
+ rule);
// We need to set those in case we are not respecting clear top.
// TODO(b/231845476) we should always respect clearTop.
@@ -917,39 +983,42 @@ public class SplitControllerTest {
secondaryContainer.setLastRequestedBounds(getSplitBounds(false /* isPrimary */));
}
- /** Gets the bounds of a TaskFragment that is in split. */
- private Rect getSplitBounds(boolean isPrimary) {
- final int width = (int) (TASK_BOUNDS.width() * SPLIT_RATIO);
- return isPrimary
- ? new Rect(TASK_BOUNDS.left, TASK_BOUNDS.top, TASK_BOUNDS.left + width,
- TASK_BOUNDS.bottom)
- : new Rect(TASK_BOUNDS.left + width, TASK_BOUNDS.top, TASK_BOUNDS.right,
- TASK_BOUNDS.bottom);
+ /** Asserts that the two given activities are in split. */
+ private void assertSplitPair(@NonNull Activity primaryActivity,
+ @NonNull Activity secondaryActivity) {
+ assertSplitPair(primaryActivity, secondaryActivity, false /* matchParentBounds */);
}
/** Asserts that the two given activities are in split. */
private void assertSplitPair(@NonNull Activity primaryActivity,
- @NonNull Activity secondaryActivity) {
+ @NonNull Activity secondaryActivity, boolean matchParentBounds) {
assertSplitPair(mSplitController.getContainerWithActivity(primaryActivity),
- mSplitController.getContainerWithActivity(secondaryActivity));
+ mSplitController.getContainerWithActivity(secondaryActivity), matchParentBounds);
}
- /** Asserts that the two given TaskFragments are in split. */
private void assertSplitPair(@NonNull TaskFragmentContainer primaryContainer,
@NonNull TaskFragmentContainer secondaryContainer) {
+ assertSplitPair(primaryContainer, secondaryContainer, false /* matchParentBounds*/);
+ }
+
+ /** Asserts that the two given TaskFragments are in split. */
+ private void assertSplitPair(@NonNull TaskFragmentContainer primaryContainer,
+ @NonNull TaskFragmentContainer secondaryContainer, boolean matchParentBounds) {
assertNotNull(primaryContainer);
assertNotNull(secondaryContainer);
assertNotNull(mSplitController.getActiveSplitForContainers(primaryContainer,
secondaryContainer));
if (primaryContainer.mInfo != null) {
- assertTrue(primaryContainer.areLastRequestedBoundsEqual(
- getSplitBounds(true /* isPrimary */)));
+ final Rect primaryBounds = matchParentBounds ? new Rect()
+ : getSplitBounds(true /* isPrimary */);
+ assertTrue(primaryContainer.areLastRequestedBoundsEqual(primaryBounds));
assertTrue(primaryContainer.isLastRequestedWindowingModeEqual(
WINDOWING_MODE_MULTI_WINDOW));
}
if (secondaryContainer.mInfo != null) {
- assertTrue(secondaryContainer.areLastRequestedBoundsEqual(
- getSplitBounds(false /* isPrimary */)));
+ final Rect secondaryBounds = matchParentBounds ? new Rect()
+ : getSplitBounds(false /* isPrimary */);
+ assertTrue(secondaryContainer.areLastRequestedBoundsEqual(secondaryBounds));
assertTrue(secondaryContainer.isLastRequestedWindowingModeEqual(
WINDOWING_MODE_MULTI_WINDOW));
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
index 906e9904566f..acc398a27baf 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
@@ -18,25 +18,44 @@ package androidx.window.extensions.embedding;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_BOUNDS;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitRule;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.getSplitBounds;
+import static androidx.window.extensions.embedding.SplitPresenter.POSITION_END;
+import static androidx.window.extensions.embedding.SplitPresenter.POSITION_FILL;
+import static androidx.window.extensions.embedding.SplitPresenter.POSITION_START;
+import static androidx.window.extensions.embedding.SplitPresenter.getBoundsForPosition;
+import static androidx.window.extensions.embedding.SplitPresenter.getMinDimensions;
+import static androidx.window.extensions.embedding.SplitPresenter.shouldShowSideBySide;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
+import android.util.Pair;
+import android.util.Size;
import android.window.TaskFragmentInfo;
import android.window.WindowContainerTransaction;
+import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -56,8 +75,6 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SplitPresenterTest {
- private static final int TASK_ID = 10;
- private static final Rect TASK_BOUNDS = new Rect(0, 0, 600, 1200);
@Mock
private Activity mActivity;
@@ -77,11 +94,7 @@ public class SplitPresenterTest {
mPresenter = mController.mPresenter;
spyOn(mController);
spyOn(mPresenter);
- final Configuration activityConfig = new Configuration();
- activityConfig.windowConfiguration.setBounds(TASK_BOUNDS);
- activityConfig.windowConfiguration.setMaxBounds(TASK_BOUNDS);
- doReturn(mActivityResources).when(mActivity).getResources();
- doReturn(activityConfig).when(mActivityResources).getConfiguration();
+ mActivity = createMockActivity();
}
@Test
@@ -129,4 +142,67 @@ public class SplitPresenterTest {
verify(mTransaction, never()).setWindowingMode(any(), anyInt());
}
+
+ @Test
+ public void testGetMinDimensionsForIntent() {
+ final Intent intent = new Intent(ApplicationProvider.getApplicationContext(),
+ MinimumDimensionActivity.class);
+ assertEquals(new Size(600, 1200), getMinDimensions(intent));
+ }
+
+ @Test
+ public void testShouldShowSideBySide() {
+ Activity secondaryActivity = createMockActivity();
+ final SplitRule splitRule = createSplitRule(mActivity, secondaryActivity);
+
+ assertTrue(shouldShowSideBySide(TASK_BOUNDS, splitRule));
+
+ // Set minDimensions of primary container to larger than primary bounds.
+ final Rect primaryBounds = getSplitBounds(true /* isPrimary */);
+ Pair<Size, Size> minDimensionsPair = new Pair<>(
+ new Size(primaryBounds.width() + 1, primaryBounds.height() + 1), null);
+
+ assertFalse(shouldShowSideBySide(TASK_BOUNDS, splitRule, minDimensionsPair));
+ }
+
+ @Test
+ public void testGetBoundsForPosition() {
+ Activity secondaryActivity = createMockActivity();
+ final SplitRule splitRule = createSplitRule(mActivity, secondaryActivity);
+ final Rect primaryBounds = getSplitBounds(true /* isPrimary */);
+ final Rect secondaryBounds = getSplitBounds(false /* isPrimary */);
+
+ assertEquals("Primary bounds must be reported.",
+ primaryBounds,
+ getBoundsForPosition(POSITION_START, TASK_BOUNDS, splitRule,
+ mActivity, null /* miniDimensionsPair */));
+
+ assertEquals("Secondary bounds must be reported.",
+ secondaryBounds,
+ getBoundsForPosition(POSITION_END, TASK_BOUNDS, splitRule,
+ mActivity, null /* miniDimensionsPair */));
+ assertEquals("Task bounds must be reported.",
+ new Rect(),
+ getBoundsForPosition(POSITION_FILL, TASK_BOUNDS, splitRule,
+ mActivity, null /* miniDimensionsPair */));
+
+ Pair<Size, Size> minDimensionsPair = new Pair<>(
+ new Size(primaryBounds.width() + 1, primaryBounds.height() + 1), null);
+
+ assertEquals("Fullscreen bounds must be reported because of min dimensions.",
+ new Rect(),
+ getBoundsForPosition(POSITION_START, TASK_BOUNDS,
+ splitRule, mActivity, minDimensionsPair));
+ }
+
+ private Activity createMockActivity() {
+ final Activity activity = mock(Activity.class);
+ final Configuration activityConfig = new Configuration();
+ activityConfig.windowConfiguration.setBounds(TASK_BOUNDS);
+ activityConfig.windowConfiguration.setMaxBounds(TASK_BOUNDS);
+ doReturn(mActivityResources).when(activity).getResources();
+ doReturn(activityConfig).when(mActivityResources).getConfiguration();
+ doReturn(new ActivityInfo()).when(activity).getActivityInfo();
+ return activity;
+ }
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
index ebe202db4e54..dd67e48ef353 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
@@ -22,6 +22,9 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_BOUNDS;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
@@ -53,9 +56,6 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TaskContainerTest {
- private static final int TASK_ID = 10;
- private static final Rect TASK_BOUNDS = new Rect(0, 0, 600, 1200);
-
@Mock
private SplitController mController;
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java
index af3ad70c04db..d31342bfb309 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java
@@ -16,6 +16,8 @@
package androidx.window.extensions.embedding;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -43,8 +45,6 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TaskFragmentAnimationControllerTest {
- private static final int TASK_ID = 10;
-
@Mock
private TaskFragmentOrganizer mOrganizer;
private TaskFragmentAnimationController mAnimationController;
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
index fcbd8a3ac020..28c2773e25cb 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
@@ -16,6 +16,9 @@
package androidx.window.extensions.embedding;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.createMockTaskFragmentInfo;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static org.junit.Assert.assertEquals;
@@ -30,17 +33,13 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
-import android.annotation.NonNull;
import android.app.Activity;
import android.content.Intent;
-import android.content.res.Configuration;
-import android.graphics.Point;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.window.TaskFragmentInfo;
-import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -55,7 +54,6 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
/**
@@ -68,8 +66,6 @@ import java.util.List;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TaskFragmentContainerTest {
- private static final int TASK_ID = 10;
-
@Mock
private SplitPresenter mPresenter;
@Mock
@@ -311,18 +307,4 @@ public class TaskFragmentContainerTest {
doReturn(activity).when(mController).getActivity(activityToken);
return activity;
}
-
- /** Creates a mock TaskFragmentInfo for the given TaskFragment. */
- private TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container,
- @NonNull Activity activity) {
- return new TaskFragmentInfo(container.getTaskFragmentToken(),
- mock(WindowContainerToken.class),
- new Configuration(),
- 1,
- true /* isVisible */,
- Collections.singletonList(activity.getActivityToken()),
- new Point(),
- false /* isTaskClearedForReuse */,
- false /* isTaskFragmentClearedForPip */);
- }
}
diff --git a/libs/WindowManager/Shell/res/values-af/strings_tv.xml b/libs/WindowManager/Shell/res/values-af/strings_tv.xml
index c87bec093cca..6187ea46769c 100644
--- a/libs/WindowManager/Shell/res/values-af/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Beeld-in-beeld"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Titellose program)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Maak PIP toe"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Maak toe"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Volskerm"</string>
- <string name="pip_move" msgid="1544227837964635439">"Skuif PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Vou PIP uit"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Vou PIP in"</string>
+ <string name="pip_move" msgid="158770205886688553">"Skuif"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Vou uit"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Vou in"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Dubbeldruk "<annotation icon="home_icon">" TUIS "</annotation>" vir kontroles"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Prent-in-prent-kieslys"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Skuif links"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Skuif regs"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Skuif op"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Skuif af"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Klaar"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-am/strings_tv.xml b/libs/WindowManager/Shell/res/values-am/strings_tv.xml
index d23353858de6..74ce49ef078e 100644
--- a/libs/WindowManager/Shell/res/values-am/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ስዕል-ላይ-ስዕል"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ርዕስ የሌለው ፕሮግራም)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIPን ዝጋ"</string>
+ <string name="pip_close" msgid="2955969519031223530">"ዝጋ"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"ሙሉ ማያ ገጽ"</string>
- <string name="pip_move" msgid="1544227837964635439">"ፒአይፒ ውሰድ"</string>
- <string name="pip_expand" msgid="7605396312689038178">"ፒአይፒን ዘርጋ"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"ፒአይፒን ሰብስብ"</string>
+ <string name="pip_move" msgid="158770205886688553">"ውሰድ"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"ዘርጋ"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"ሰብስብ"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" ለመቆጣጠሪያዎች "<annotation icon="home_icon">"መነሻ"</annotation>"ን ሁለቴ ይጫኑ"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"የስዕል-ላይ-ስዕል ምናሌ።"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ወደ ግራ ውሰድ"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"ወደ ቀኝ ውሰድ"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ወደ ላይ ውሰድ"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"ወደ ታች ውሰድ"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"ተጠናቅቋል"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings_tv.xml b/libs/WindowManager/Shell/res/values-ar/strings_tv.xml
index a1ceda5fc987..9c195a7386a9 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"نافذة ضمن النافذة"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ليس هناك عنوان للبرنامج)"</string>
- <string name="pip_close" msgid="9135220303720555525">"‏إغلاق PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"إغلاق"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"ملء الشاشة"</string>
- <string name="pip_move" msgid="1544227837964635439">"‏نقل نافذة داخل النافذة (PIP)"</string>
- <string name="pip_expand" msgid="7605396312689038178">"‏توسيع نافذة داخل النافذة (PIP)"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"‏تصغير نافذة داخل النافذة (PIP)"</string>
+ <string name="pip_move" msgid="158770205886688553">"نقل"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"توسيع"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"تصغير"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" انقر مرتين على "<annotation icon="home_icon">" الصفحة الرئيسية "</annotation>" للوصول لعناصر التحكم."</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"قائمة نافذة ضمن النافذة"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"نقل لليسار"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"نقل لليمين"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"نقل للأعلى"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"نقل للأسفل"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"تمّ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-as/strings_tv.xml b/libs/WindowManager/Shell/res/values-as/strings_tv.xml
index 8d7bd9f6a27e..816b5b1c79dc 100644
--- a/libs/WindowManager/Shell/res/values-as/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"চিত্ৰৰ ভিতৰত চিত্ৰ"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(শিৰোনামবিহীন কাৰ্যক্ৰম)"</string>
- <string name="pip_close" msgid="9135220303720555525">"পিপ বন্ধ কৰক"</string>
+ <string name="pip_close" msgid="2955969519031223530">"বন্ধ কৰক"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"সম্পূৰ্ণ স্ক্ৰীন"</string>
- <string name="pip_move" msgid="1544227837964635439">"পিপ স্থানান্তৰ কৰক"</string>
- <string name="pip_expand" msgid="7605396312689038178">"পিপ বিস্তাৰ কৰক"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"পিপ সংকোচন কৰক"</string>
+ <string name="pip_move" msgid="158770205886688553">"স্থানান্তৰ কৰক"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"বিস্তাৰ কৰক"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"সংকোচন কৰক"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" নিয়ন্ত্ৰণৰ বাবে "<annotation icon="home_icon">" গৃহপৃষ্ঠা "</annotation>" বুটামত দুবাৰ হেঁচক"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"চিত্ৰৰ ভিতৰৰ চিত্ৰ মেনু।"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"বাওঁফাললৈ নিয়ক"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"সোঁফাললৈ নিয়ক"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ওপৰলৈ নিয়ক"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"তললৈ নিয়ক"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"হ’ল"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-az/strings_tv.xml b/libs/WindowManager/Shell/res/values-az/strings_tv.xml
index 87c46fa41a01..ccb7a7069ad8 100644
--- a/libs/WindowManager/Shell/res/values-az/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Şəkil-içində-Şəkil"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Başlıqsız proqram)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP bağlayın"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Bağlayın"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Tam ekran"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP tətbiq edin"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIP-ni genişləndirin"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIP-ni yığcamlaşdırın"</string>
+ <string name="pip_move" msgid="158770205886688553">"Köçürün"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Genişləndirin"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Yığcamlaşdırın"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Nizamlayıcılar üçün "<annotation icon="home_icon">" ƏSAS SƏHİFƏ "</annotation>" süçimini iki dəfə basın"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Şəkildə şəkil menyusu."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Sola köçürün"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Sağa köçürün"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Yuxarı köçürün"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Aşağı köçürün"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Hazırdır"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml
index c87f30611a07..51a1262b1de7 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Slika u slici"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program bez naslova)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Zatvori PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Zatvori"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Ceo ekran"</string>
- <string name="pip_move" msgid="1544227837964635439">"Premesti sliku u slici"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Proširi sliku u slici"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Skupi sliku u slici"</string>
+ <string name="pip_move" msgid="158770205886688553">"Premesti"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Proširi"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Skupi"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Dvaput pritisnite "<annotation icon="home_icon">" HOME "</annotation>" za kontrole"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Meni Slika u slici."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Pomerite nalevo"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Pomerite nadesno"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Pomerite nagore"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Pomerite nadole"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Gotovo"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-be/strings_tv.xml b/libs/WindowManager/Shell/res/values-be/strings_tv.xml
index 3566bc372820..15a353c649d6 100644
--- a/libs/WindowManager/Shell/res/values-be/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Відарыс у відарысе"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Праграма без назвы)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Закрыць PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Закрыць"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Поўнаэкранны рэжым"</string>
- <string name="pip_move" msgid="1544227837964635439">"Перамясціць PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Разгарнуць відарыс у відарысе"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Згарнуць відарыс у відарысе"</string>
+ <string name="pip_move" msgid="158770205886688553">"Перамясціць"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Разгарнуць"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Згарнуць"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Двойчы націсніце "<annotation icon="home_icon">" ГАЛОЎНЫ ЭКРАН "</annotation>" для пераходу ў налады"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Меню рэжыму \"Відарыс у відарысе\"."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Перамясціць улева"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Перамясціць управа"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Перамясціць уверх"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Перамясціць уніз"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Гатова"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings_tv.xml b/libs/WindowManager/Shell/res/values-bg/strings_tv.xml
index 91049fd2cf02..2b27a6927077 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Картина в картината"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Програма без заглавие)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Затваряне на PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Затваряне"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Цял екран"</string>
- <string name="pip_move" msgid="1544227837964635439">"„Картина в картина“: Преместв."</string>
- <string name="pip_expand" msgid="7605396312689038178">"Разгъване на прозореца за PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Свиване на прозореца за PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Преместване"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Разгъване"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Свиване"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" За достъп до контролите натиснете 2 пъти "<annotation icon="home_icon">"НАЧАЛО"</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Меню за функцията „Картина в картината“."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Преместване наляво"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Преместване надясно"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Преместване нагоре"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Преместване надолу"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Готово"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings_tv.xml b/libs/WindowManager/Shell/res/values-bn/strings_tv.xml
index 792708d128a5..23c8ffabeede 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ছবির-মধ্যে-ছবি"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(শিরোনামহীন প্রোগ্রাম)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP বন্ধ করুন"</string>
+ <string name="pip_close" msgid="2955969519031223530">"বন্ধ করুন"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"পূর্ণ স্ক্রিন"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP সরান"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIP বড় করুন"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIP আড়াল করুন"</string>
+ <string name="pip_move" msgid="158770205886688553">"সরান"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"বড় করুন"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"আড়াল করুন"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" কন্ট্রোলের জন্য "<annotation icon="home_icon">" হোম "</annotation>" বোতামে ডবল প্রেস করুন"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"ছবির-মধ্যে-ছবি মেনু।"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"বাঁদিকে সরান"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"ডানদিকে সরান"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"উপরে তুলুন"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"নিচে নামান"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"হয়ে গেছে"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings_tv.xml b/libs/WindowManager/Shell/res/values-bs/strings_tv.xml
index b7f0dca1b5a5..443fd620fd65 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Slika u slici"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program bez naslova)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Zatvori sliku u slici"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Zatvori"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Cijeli ekran"</string>
- <string name="pip_move" msgid="1544227837964635439">"Pokreni sliku u slici"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Proširi sliku u slici"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Suzi sliku u slici"</string>
+ <string name="pip_move" msgid="158770205886688553">"Premjesti"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Proširi"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Suzi"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Dvaput pritisnite "<annotation icon="home_icon">" POČETNI EKRAN "</annotation>" za kontrole"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Meni za način rada slika u slici."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Pomjeranje ulijevo"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Pomjeranje udesno"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Pomjeranje nagore"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Pomjeranje nadolje"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Gotovo"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings_tv.xml b/libs/WindowManager/Shell/res/values-ca/strings_tv.xml
index 1c560c7afa06..94ba0db7e978 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Pantalla en pantalla"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programa sense títol)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Tanca PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Tanca"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Pantalla completa"</string>
- <string name="pip_move" msgid="1544227837964635439">"Mou pantalla en pantalla"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Desplega pantalla en pantalla"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Replega pantalla en pantalla"</string>
+ <string name="pip_move" msgid="158770205886688553">"Mou"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Desplega"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Replega"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Prem dos cops "<annotation icon="home_icon">" INICI "</annotation>" per accedir als controls"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menú de pantalla en pantalla."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mou cap a l\'esquerra"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mou cap a la dreta"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mou cap amunt"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Mou cap avall"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Fet"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings_tv.xml b/libs/WindowManager/Shell/res/values-cs/strings_tv.xml
index 9a8cc2b4d70e..3ed85dce0433 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Obraz v obraze"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Bez názvu)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Ukončit obraz v obraze (PIP)"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Zavřít"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Celá obrazovka"</string>
- <string name="pip_move" msgid="1544227837964635439">"Přesunout PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Rozbalit PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Sbalit PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Přesunout"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Rozbalit"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Sbalit"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Ovládací prvky zobrazíte dvojitým stisknutím "<annotation icon="home_icon">"tlačítka plochy"</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Nabídka režimu obrazu v obraze"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Přesunout doleva"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Přesunout doprava"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Přesunout nahoru"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Přesunout dolů"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Hotovo"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-da/strings_tv.xml b/libs/WindowManager/Shell/res/values-da/strings_tv.xml
index cba660ac723c..09024428a825 100644
--- a/libs/WindowManager/Shell/res/values-da/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Integreret billede"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program uden titel)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Luk integreret billede"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Luk"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Fuld skærm"</string>
- <string name="pip_move" msgid="1544227837964635439">"Flyt PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Udvid PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Skjul PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Flyt"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Udvid"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Skjul"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Tryk to gange på "<annotation icon="home_icon">" HJEM "</annotation>" for at se indstillinger"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu for integreret billede."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Flyt til venstre"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Flyt til højre"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Flyt op"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Flyt ned"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Udfør"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-de/strings_tv.xml b/libs/WindowManager/Shell/res/values-de/strings_tv.xml
index 02a1b66eb63f..18535c9d9338 100644
--- a/libs/WindowManager/Shell/res/values-de/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Bild im Bild"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Kein Sendungsname gefunden)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP schließen"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Schließen"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Vollbild"</string>
- <string name="pip_move" msgid="1544227837964635439">"BiB verschieben"</string>
- <string name="pip_expand" msgid="7605396312689038178">"BiB maximieren"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"BiB minimieren"</string>
+ <string name="pip_move" msgid="158770205886688553">"Bewegen"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Maximieren"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Minimieren"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Für Steuerelemente zweimal "<annotation icon="home_icon">"STARTBILDSCHIRMTASTE"</annotation>" drücken"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menü „Bild im Bild“."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Nach links bewegen"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Nach rechts bewegen"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Nach oben bewegen"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Nach unten bewegen"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Fertig"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-el/strings_tv.xml b/libs/WindowManager/Shell/res/values-el/strings_tv.xml
index 24cd030cd754..5f8a004b0a1f 100644
--- a/libs/WindowManager/Shell/res/values-el/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-Picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Δεν υπάρχει τίτλος προγράμματος)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Κλείσιμο PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Κλείσιμο"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Πλήρης οθόνη"</string>
- <string name="pip_move" msgid="1544227837964635439">"Μετακίνηση PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Ανάπτυξη PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Σύμπτυξη PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Μετακίνηση"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Ανάπτυξη"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Σύμπτυξη"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Πατήστε δύο φορές "<annotation icon="home_icon">" ΑΡΧΙΚΗ ΟΘΟΝΗ "</annotation>" για στοιχεία ελέγχου"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Μενού λειτουργίας Picture-in-Picture."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Μετακίνηση αριστερά"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Μετακίνηση δεξιά"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Μετακίνηση επάνω"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Μετακίνηση κάτω"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Τέλος"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml
index 82257b42814d..839789b22a1c 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(No title program)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Close PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Close"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Full screen"</string>
- <string name="pip_move" msgid="1544227837964635439">"Move PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Expand PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Collapse PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Move"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Expand"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Collapse"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Double-press "<annotation icon="home_icon">" HOME "</annotation>" for controls"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Picture-in-picture menu"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Move left"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Move right"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Move up"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Move down"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Done"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml
index 82257b42814d..839789b22a1c 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(No title program)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Close PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Close"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Full screen"</string>
- <string name="pip_move" msgid="1544227837964635439">"Move PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Expand PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Collapse PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Move"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Expand"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Collapse"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Double-press "<annotation icon="home_icon">" HOME "</annotation>" for controls"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Picture-in-picture menu"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Move left"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Move right"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Move up"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Move down"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Done"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml
index 82257b42814d..839789b22a1c 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(No title program)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Close PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Close"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Full screen"</string>
- <string name="pip_move" msgid="1544227837964635439">"Move PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Expand PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Collapse PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Move"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Expand"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Collapse"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Double-press "<annotation icon="home_icon">" HOME "</annotation>" for controls"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Picture-in-picture menu"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Move left"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Move right"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Move up"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Move down"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Done"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml
index 82257b42814d..839789b22a1c 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(No title program)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Close PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Close"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Full screen"</string>
- <string name="pip_move" msgid="1544227837964635439">"Move PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Expand PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Collapse PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Move"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Expand"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Collapse"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Double-press "<annotation icon="home_icon">" HOME "</annotation>" for controls"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Picture-in-picture menu"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Move left"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Move right"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Move up"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Move down"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Done"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml
index a6e494cfed3c..507e066e3812 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‎‎‏‎‎‎‏‏‏‎‏‎‎‏‎‏‎‏‏‎‎‏‎‎‏‏‏‎‎‎‎‎‏‏‎‎‏‏‎‎‎‎‏‎‎‎‎‎‎‎‏‏‎Picture-in-Picture‎‏‎‎‏‎"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‏‎(No title program)‎‏‎‎‏‎"</string>
- <string name="pip_close" msgid="9135220303720555525">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‏‎‎‏‎‎‏‏‏‎‏‏‏‎‎‏‏‏‏‎‎‎‎‏‏‎‎‏‏‎‎‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎Close PIP‎‏‎‎‏‎"</string>
+ <string name="pip_close" msgid="2955969519031223530">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‎‏‎‎‏‏‏‎‏‏‎‏‏‏‏‎‎‏‎‏‏‏‏‎‏‎‎‎‎‎‏‎‎‏‏‏‎‏‎‏‎‎Close‎‏‎‎‏‎"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‎‎‎‏‏‎‏‎‎‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‎‏‎‏‎‎‏‎‎‎‎‎‎‎‏‎‎‏‏‎‎‏‏‎‏‎‎Full screen‎‏‎‎‏‎"</string>
- <string name="pip_move" msgid="1544227837964635439">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‎‏‏‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎‏‏‎‎‏‏‎‏‎‎‏‎‏‏‏‏‎Move PIP‎‏‎‎‏‎"</string>
- <string name="pip_expand" msgid="7605396312689038178">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‎‏‏‏‏‎‎‏‎‏‏‏‎‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‏‏‎‎‏‎‏‎‏‎‏‎‎‏‏‎‏‏‎‎‎‏‎‎Expand PIP‎‏‎‎‏‎"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‎‏‎‎‎‎‏‎‎‏‎‏‏‎‏‏‎‏‏‏‏‎‎Collapse PIP‎‏‎‎‏‎"</string>
+ <string name="pip_move" msgid="158770205886688553">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‎‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‎‎‏‏‏‎‏‎‏‏‎‎‏‎‏‎‏‎‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎Move‎‏‎‎‏‎"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‎‏‎‏‎‏‎‏‏‎‎‎‎‎‏‏‏‎‎‏‏‎‎‏‏‏‏‎‏‏‎‏‏‏‎‎‏‏‏‏‎‎‎‏‏‏‎‎‎Expand‎‏‎‎‏‎"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‏‎‏‏‎‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‏‏‎‎‎‎‏‎‏‎‏‏‎‎‏‏‏‏‎‏‎‏‎‎Collapse‎‏‎‎‏‎"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‏‏‎‎‏‎‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‏‎‎‎‎‎‎‏‎‏‏‎‏‏‏‎‏‎ Double press ‎‏‎‎‏‏‎"<annotation icon="home_icon">"‎‏‎‎‏‏‏‎ HOME ‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎ for controls‎‏‎‎‏‎"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‎‏‏‏‎‏‎‏‏‎‎‎‎‎‎‎‎‏‏‎‎‏‎‏‏‎‏‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‏‎‎‏‏‏‎‎Picture-in-Picture menu.‎‏‎‎‏‎"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‎‏‏‎‎‎‎‎‎‏‏‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‎‏‎‎‎‎‎‏‎‏‎‎‏‏‎‎‎‏‎‏‎‎‏‏‏‏‎Move left‎‏‎‎‏‎"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‎‎‎‏‎‎‎‏‏‏‏‎‎‎‎‏‎‏‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎‎‏‏‏‏‎‎‏‎‏‎‏‎‏‎‏‎‏‎‎‎‎‎Move right‎‏‎‎‏‎"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‏‎‏‏‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‏‏‏‎‏‏‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎Move up‎‏‎‎‏‎"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎‎‎‏‎‏‏‏‎‏‏‎‏‎‎‎‏‏‎‏‏‎‏‏‎‏‎‏‎‏‎‏‏‏‏‎‎‏‏‏‏‎‎‎Move down‎‏‎‎‏‎"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‎‎‏‎‎‏‎‏‎‏‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‎‏‎‏‏‏‎‏‏‎‎‏‎‏‎‏‎‎‏‎‎Done‎‏‎‎‏‎"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml
index 458f6b15b857..a2c27b79e04c 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Pantalla en pantalla"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Sin título de programa)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Cerrar PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Cerrar"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Pantalla completa"</string>
- <string name="pip_move" msgid="1544227837964635439">"Mover PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Maximizar PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Minimizar PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Mover"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Expandir"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Contraer"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Presiona dos veces "<annotation icon="home_icon">"INICIO"</annotation>" para ver los controles"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menú de pantalla en pantalla"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mover hacia la izquierda"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mover hacia la derecha"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mover hacia arriba"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Mover hacia abajo"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Listo"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-es/strings_tv.xml b/libs/WindowManager/Shell/res/values-es/strings_tv.xml
index 0a690984dac5..7993e03b2464 100644
--- a/libs/WindowManager/Shell/res/values-es/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Imagen en imagen"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programa sin título)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Cerrar PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Cerrar"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Pantalla completa"</string>
- <string name="pip_move" msgid="1544227837964635439">"Mover imagen en imagen"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Mostrar imagen en imagen"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Ocultar imagen en imagen"</string>
+ <string name="pip_move" msgid="158770205886688553">"Mover"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Mostrar"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Ocultar"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Pulsa dos veces "<annotation icon="home_icon">"INICIO"</annotation>" para ver los controles"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menú de imagen en imagen."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mover hacia la izquierda"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mover hacia la derecha"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mover hacia arriba"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Mover hacia abajo"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Hecho"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-et/strings_tv.xml b/libs/WindowManager/Shell/res/values-et/strings_tv.xml
index dc0232303a70..e8fcb180c0c4 100644
--- a/libs/WindowManager/Shell/res/values-et/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Pilt pildis"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programmi pealkiri puudub)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Sule PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Sule"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Täisekraan"</string>
- <string name="pip_move" msgid="1544227837964635439">"Teisalda PIP-režiimi"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Laienda PIP-akent"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Ahenda PIP-aken"</string>
+ <string name="pip_move" msgid="158770205886688553">"Teisalda"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Laienda"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Ahenda"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Nuppude nägemiseks vajutage 2 korda nuppu "<annotation icon="home_icon">"AVAKUVA"</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menüü Pilt pildis."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Teisalda vasakule"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Teisalda paremale"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Teisalda üles"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Teisalda alla"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Valmis"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings_tv.xml b/libs/WindowManager/Shell/res/values-eu/strings_tv.xml
index bce06da2c66f..07d75d2de9cd 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Pantaila txiki gainjarria"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programa izengabea)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Itxi PIPa"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Itxi"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Pantaila osoa"</string>
- <string name="pip_move" msgid="1544227837964635439">"Mugitu pantaila txiki gainjarria"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Zabaldu pantaila txiki gainjarria"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Tolestu pantaila txiki gainjarria"</string>
+ <string name="pip_move" msgid="158770205886688553">"Mugitu"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Zabaldu"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Tolestu"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Kontrolatzeko aukerak atzitzeko, sakatu birritan "<annotation icon="home_icon">" HASIERA "</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Pantaila txiki gainjarriaren menua."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Eraman ezkerrera"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Eraman eskuinera"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Eraman gora"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Eraman behera"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Eginda"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings_tv.xml b/libs/WindowManager/Shell/res/values-fa/strings_tv.xml
index ff9a03c6cefb..03f51d01a3a8 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"تصویر در تصویر"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(برنامه بدون عنوان)"</string>
- <string name="pip_close" msgid="9135220303720555525">"‏بستن PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"بستن"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"تمام صفحه"</string>
- <string name="pip_move" msgid="1544227837964635439">"‏انتقال PIP (تصویر در تصویر)"</string>
- <string name="pip_expand" msgid="7605396312689038178">"گسترده کردن «تصویر در تصویر»"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"جمع کردن «تصویر در تصویر»"</string>
+ <string name="pip_move" msgid="158770205886688553">"انتقال"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"گسترده کردن"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"جمع کردن"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" برای کنترل‌ها، دکمه "<annotation icon="home_icon">"صفحه اصلی"</annotation>" را دوبار فشار دهید"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"منوی تصویر در تصویر."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"انتقال به‌چپ"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"انتقال به‌راست"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"انتقال به‌بالا"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"انتقال به‌پایین"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"تمام"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings_tv.xml b/libs/WindowManager/Shell/res/values-fi/strings_tv.xml
index 3e8bf9032780..24ab7d99e180 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Kuva kuvassa"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Nimetön)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Sulje PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Sulje"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Koko näyttö"</string>
- <string name="pip_move" msgid="1544227837964635439">"Siirrä PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Laajenna PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Tiivistä PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Siirrä"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Laajenna"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Tiivistä"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Asetukset: paina "<annotation icon="home_icon">"ALOITUSNÄYTTÖPAINIKETTA"</annotation>" kahdesti"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Kuva kuvassa ‑valikko."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Siirrä vasemmalle"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Siirrä oikealle"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Siirrä ylös"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Siirrä alas"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Valmis"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml
index 66e13b89c64b..87651ec711d9 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Incrustation d\'image"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Aucun programme de titre)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Fermer mode IDI"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Fermer"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Plein écran"</string>
- <string name="pip_move" msgid="1544227837964635439">"Déplacer l\'image incrustée"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Développer l\'image incrustée"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Réduire l\'image incrustée"</string>
+ <string name="pip_move" msgid="158770205886688553">"Déplacer"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Développer"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Réduire"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Appuyez deux fois sur "<annotation icon="home_icon">" ACCUEIL "</annotation>" pour les commandes"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu d\'incrustation d\'image."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Déplacer vers la gauche"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Déplacer vers la droite"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Déplacer vers le haut"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Déplacer vers le bas"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings_tv.xml b/libs/WindowManager/Shell/res/values-fr/strings_tv.xml
index ed9baf5b6215..37863fb82295 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programme sans titre)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Fermer mode PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Fermer"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Plein écran"</string>
- <string name="pip_move" msgid="1544227837964635439">"Déplacer le PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Développer la fenêtre PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Réduire la fenêtre PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Déplacer"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Développer"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Réduire"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Menu de commandes : appuyez deux fois sur "<annotation icon="home_icon">"ACCUEIL"</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu \"Picture-in-picture\"."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Déplacer vers la gauche"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Déplacer vers la droite"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Déplacer vers le haut"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Déplacer vers le bas"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"OK"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings_tv.xml b/libs/WindowManager/Shell/res/values-gl/strings_tv.xml
index a057434d7853..5d6de76c4deb 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Pantalla superposta"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programa sen título)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Pechar PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Pechar"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Pantalla completa"</string>
- <string name="pip_move" msgid="1544227837964635439">"Mover pantalla superposta"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Despregar pantalla superposta"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Contraer pantalla superposta"</string>
+ <string name="pip_move" msgid="158770205886688553">"Mover"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Despregar"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Contraer"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Preme "<annotation icon="home_icon">"INICIO"</annotation>" dúas veces para acceder aos controis"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menú de pantalla superposta."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mover cara á esquerda"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mover cara á dereita"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mover cara arriba"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Mover cara abaixo"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Feito"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings_tv.xml b/libs/WindowManager/Shell/res/values-gu/strings_tv.xml
index d9525910e4c6..6c1b9db73582 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ચિત્રમાં-ચિત્ર"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(કોઈ ટાઇટલ પ્રોગ્રામ નથી)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP બંધ કરો"</string>
+ <string name="pip_close" msgid="2955969519031223530">"બંધ કરો"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"પૂર્ણ સ્ક્રીન"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP ખસેડો"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIP મોટી કરો"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIP નાની કરો"</string>
+ <string name="pip_move" msgid="158770205886688553">"ખસેડો"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"મોટું કરો"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"નાનું કરો"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" નિયંત્રણો માટે "<annotation icon="home_icon">" હોમ "</annotation>" બટન પર બે વાર દબાવો"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"ચિત્રમાં ચિત્ર મેનૂ."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ડાબે ખસેડો"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"જમણે ખસેડો"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ઉપર ખસેડો"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"નીચે ખસેડો"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"થઈ ગયું"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings_tv.xml b/libs/WindowManager/Shell/res/values-hi/strings_tv.xml
index d897ac73f80d..e0227253b2dc 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"पिक्चर में पिक्चर"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(कोई शीर्षक कार्यक्रम नहीं)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP बंद करें"</string>
+ <string name="pip_close" msgid="2955969519031223530">"बंद करें"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"फ़ुल स्‍क्रीन"</string>
- <string name="pip_move" msgid="1544227837964635439">"पीआईपी को दूसरी जगह लेकर जाएं"</string>
- <string name="pip_expand" msgid="7605396312689038178">"पीआईपी विंडो को बड़ा करें"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"पीआईपी विंडो को छोटा करें"</string>
+ <string name="pip_move" msgid="158770205886688553">"ले जाएं"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"बड़ा करें"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"छोटा करें"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" कंट्रोल मेन्यू पर जाने के लिए, "<annotation icon="home_icon">" होम बटन"</annotation>" दो बार दबाएं"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"पिक्चर में पिक्चर मेन्यू."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"बाईं ओर ले जाएं"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"दाईं ओर ले जाएं"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ऊपर ले जाएं"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"नीचे ले जाएं"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"हो गया"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings_tv.xml b/libs/WindowManager/Shell/res/values-hr/strings_tv.xml
index 8f5f3164c4d7..a09e6e805f63 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Slika u slici"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program bez naslova)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Zatvori PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Zatvori"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Cijeli zaslon"</string>
- <string name="pip_move" msgid="1544227837964635439">"Premjesti PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Proširi PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Sažmi PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Premjesti"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Proširi"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Sažmi"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Dvaput pritisnite "<annotation icon="home_icon">"POČETNI ZASLON"</annotation>" za kontrole"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Izbornik slike u slici."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Pomaknite ulijevo"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Pomaknite udesno"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Pomaknite prema gore"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Pomaknite prema dolje"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Gotovo"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings_tv.xml b/libs/WindowManager/Shell/res/values-hu/strings_tv.xml
index fc8d79589121..5e065c2ad4e7 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Kép a képben"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Cím nélküli program)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP bezárása"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Bezárás"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Teljes képernyő"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP áthelyezése"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Kép a képben kibontása"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Kép a képben összecsukása"</string>
+ <string name="pip_move" msgid="158770205886688553">"Áthelyezés"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Kibontás"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Összecsukás"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Vezérlők: "<annotation icon="home_icon">" KEZDŐKÉPERNYŐ "</annotation>" gomb kétszer megnyomva"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Kép a képben menü."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mozgatás balra"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mozgatás jobbra"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mozgatás felfelé"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Mozgatás lefelé"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Kész"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings_tv.xml b/libs/WindowManager/Shell/res/values-hy/strings_tv.xml
index f5665b8dd166..7963abf8972b 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Նկար նկարի մեջ"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Առանց վերնագրի ծրագիր)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Փակել PIP-ն"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Փակել"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Լիէկրան"</string>
- <string name="pip_move" msgid="1544227837964635439">"Տեղափոխել PIP-ը"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Ծավալել PIP-ը"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Ծալել PIP-ը"</string>
+ <string name="pip_move" msgid="158770205886688553">"Տեղափոխել"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Ծավալել"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Ծալել"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Կարգավորումների համար կրկնակի սեղմեք "<annotation icon="home_icon">"ԳԼԽԱՎՈՐ ԷԿՐԱՆ"</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"«Նկար նկարի մեջ» ռեժիմի ընտրացանկ։"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Տեղափոխել ձախ"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Տեղափոխել աջ"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Տեղափոխել վերև"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Տեղափոխել ներքև"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Պատրաստ է"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-in/strings_tv.xml b/libs/WindowManager/Shell/res/values-in/strings_tv.xml
index a1535653f679..7d37154bb86c 100644
--- a/libs/WindowManager/Shell/res/values-in/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-Picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program tanpa judul)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Tutup PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Tutup"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Layar penuh"</string>
- <string name="pip_move" msgid="1544227837964635439">"Pindahkan PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Luaskan PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Ciutkan PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Pindahkan"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Luaskan"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Ciutkan"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Tekan dua kali "<annotation icon="home_icon">" HOME "</annotation>" untuk membuka kontrol"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu Picture-in-Picture."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Pindahkan ke kiri"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Pindahkan ke kanan"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Pindahkan ke atas"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Pindahkan ke bawah"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Selesai"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-is/strings_tv.xml b/libs/WindowManager/Shell/res/values-is/strings_tv.xml
index 70ca1afe3aea..1490cb98e034 100644
--- a/libs/WindowManager/Shell/res/values-is/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Mynd í mynd"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Efni án titils)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Loka mynd í mynd"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Loka"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Allur skjárinn"</string>
- <string name="pip_move" msgid="1544227837964635439">"Færa innfellda mynd"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Stækka innfellda mynd"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Minnka innfellda mynd"</string>
+ <string name="pip_move" msgid="158770205886688553">"Færa"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Stækka"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Minnka"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Ýttu tvisvar á "<annotation icon="home_icon">" HEIM "</annotation>" til að opna stillingar"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Valmynd fyrir mynd í mynd."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Færa til vinstri"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Færa til hægri"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Færa upp"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Færa niður"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Lokið"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-it/strings_tv.xml b/libs/WindowManager/Shell/res/values-it/strings_tv.xml
index cda627517872..a48516f2588e 100644
--- a/libs/WindowManager/Shell/res/values-it/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture in picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programma senza titolo)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Chiudi PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Chiudi"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Schermo intero"</string>
- <string name="pip_move" msgid="1544227837964635439">"Sposta PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Espandi PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Comprimi PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Sposta"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Espandi"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Comprimi"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Premi due volte "<annotation icon="home_icon">" HOME "</annotation>" per aprire i controlli"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu Picture in picture."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Sposta a sinistra"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Sposta a destra"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Sposta su"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Sposta giù"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Fine"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings_tv.xml b/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
index 30ce97b998ca..2af1896d3c67 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"תמונה בתוך תמונה"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(תוכנית ללא כותרת)"</string>
- <string name="pip_close" msgid="9135220303720555525">"‏סגירת PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"סגירה"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"מסך מלא"</string>
- <string name="pip_move" msgid="1544227837964635439">"‏העברת תמונה בתוך תמונה (PIP)"</string>
- <string name="pip_expand" msgid="7605396312689038178">"הרחבת חלון תמונה-בתוך-תמונה"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"כיווץ של חלון תמונה-בתוך-תמונה"</string>
+ <string name="pip_move" msgid="158770205886688553">"העברה"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"הרחבה"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"כיווץ"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" לחיצה כפולה על "<annotation icon="home_icon">" הלחצן הראשי "</annotation>" תציג את אמצעי הבקרה"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"תפריט \'תמונה בתוך תמונה\'."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"הזזה שמאלה"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"הזזה ימינה"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"הזזה למעלה"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"הזזה למטה"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"סיום"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings_tv.xml b/libs/WindowManager/Shell/res/values-ja/strings_tv.xml
index e58e7bf6fabc..bc7dcb7aa029 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ピクチャー イン ピクチャー"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(無題の番組)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP を閉じる"</string>
+ <string name="pip_close" msgid="2955969519031223530">"閉じる"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"全画面表示"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP を移動"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIP を開く"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIP を閉じる"</string>
+ <string name="pip_move" msgid="158770205886688553">"移動"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"開く"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"閉じる"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" コントロールにアクセス: "<annotation icon="home_icon">" ホーム "</annotation>" を 2 回押します"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"ピクチャー イン ピクチャーのメニューです。"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"左に移動"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"右に移動"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"上に移動"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"下に移動"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"完了"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings_tv.xml b/libs/WindowManager/Shell/res/values-ka/strings_tv.xml
index b09686646c8b..898dac2aca88 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ეკრანი ეკრანში"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(პროგრამის სათაურის გარეშე)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP-ის დახურვა"</string>
+ <string name="pip_close" msgid="2955969519031223530">"დახურვა"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"სრულ ეკრანზე"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP გადატანა"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIP-ის გაშლა"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIP-ის ჩაკეცვა"</string>
+ <string name="pip_move" msgid="158770205886688553">"გადაადგილება"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"გაშლა"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"ჩაკეცვა"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" მართვის საშუალებებზე წვდომისთვის ორმაგად დააჭირეთ "<annotation icon="home_icon">" მთავარ ღილაკს "</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"მენიუ „ეკრანი ეკრანში“."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"მარცხნივ გადატანა"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"მარჯვნივ გადატანა"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ზემოთ გადატანა"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"ქვემოთ გადატანა"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"მზადაა"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings_tv.xml b/libs/WindowManager/Shell/res/values-kk/strings_tv.xml
index 7bade0dff0d9..cdf564fb4ca0 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Суреттегі сурет"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Атаусыз бағдарлама)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP жабу"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Жабу"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Толық экран"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP клипін жылжыту"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIP терезесін жаю"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIP терезесін жию"</string>
+ <string name="pip_move" msgid="158770205886688553">"Жылжыту"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Жаю"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Жию"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Басқару элементтері: "<annotation icon="home_icon">" НЕГІЗГІ ЭКРАН "</annotation>" түймесін екі рет басыңыз."</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"\"Сурет ішіндегі сурет\" мәзірі."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Солға жылжыту"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Оңға жылжыту"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Жоғары жылжыту"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Төмен жылжыту"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Дайын"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-km/strings_tv.xml b/libs/WindowManager/Shell/res/values-km/strings_tv.xml
index 721be1fc1650..1a7ae813c1d3 100644
--- a/libs/WindowManager/Shell/res/values-km/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"រូបក្នុងរូប"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(កម្មវិធី​គ្មានចំណងជើង)"</string>
- <string name="pip_close" msgid="9135220303720555525">"បិទ PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"បិទ"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"ពេញអេក្រង់"</string>
- <string name="pip_move" msgid="1544227837964635439">"ផ្លាស់ទី PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"ពង្រីក PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"បង្រួម PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"ផ្លាស់ទី"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"ពង្រីក"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"បង្រួម"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" ចុចពីរដងលើ"<annotation icon="home_icon">"ប៊ូតុងដើម"</annotation>" ដើម្បីបើកផ្ទាំងគ្រប់គ្រង"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"ម៉ឺនុយ​រូប​ក្នុងរូប"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ផ្លាស់ទី​ទៅ​ឆ្វេង"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"ផ្លាស់ទីទៅ​ស្តាំ"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ផ្លាស់ទី​ឡើង​លើ"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"ផ្លាស់ទី​ចុះ​ក្រោម"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"រួចរាល់"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings_tv.xml b/libs/WindowManager/Shell/res/values-kn/strings_tv.xml
index 8310c8a1169c..45de068c80a0 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರ"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ಶೀರ್ಷಿಕೆ ರಹಿತ ಕಾರ್ಯಕ್ರಮ)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP ಮುಚ್ಚಿ"</string>
+ <string name="pip_close" msgid="2955969519031223530">"ಮುಚ್ಚಿರಿ"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"ಪೂರ್ಣ ಪರದೆ"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP ಅನ್ನು ಸರಿಸಿ"</string>
- <string name="pip_expand" msgid="7605396312689038178">"ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರವನ್ನು ವಿಸ್ತರಿಸಿ"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರವನ್ನು ಕುಗ್ಗಿಸಿ"</string>
+ <string name="pip_move" msgid="158770205886688553">"ಸರಿಸಿ"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"ವಿಸ್ತೃತಗೊಳಿಸಿ"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"ಕುಗ್ಗಿಸಿ"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" ಕಂಟ್ರೋಲ್‌ಗಳಿಗಾಗಿ "<annotation icon="home_icon">" ಹೋಮ್ "</annotation>" ಅನ್ನು ಎರಡು ಬಾರಿ ಒತ್ತಿ"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರ ಮೆನು."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ಎಡಕ್ಕೆ ಸರಿಸಿ"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"ಬಲಕ್ಕೆ ಸರಿಸಿ"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ಮೇಲಕ್ಕೆ ಸರಿಸಿ"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"ಕೆಳಗೆ ಸರಿಸಿ"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"ಮುಗಿದಿದೆ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings_tv.xml b/libs/WindowManager/Shell/res/values-ko/strings_tv.xml
index a3e055a515a1..9e8f1f1258a5 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"PIP 모드"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(제목 없는 프로그램)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP 닫기"</string>
+ <string name="pip_close" msgid="2955969519031223530">"닫기"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"전체화면"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP 이동"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIP 펼치기"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIP 접기"</string>
+ <string name="pip_move" msgid="158770205886688553">"이동"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"펼치기"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"접기"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" 제어 메뉴에 액세스하려면 "<annotation icon="home_icon">" 홈 "</annotation>"을 두 번 누르세요."</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"PIP 모드 메뉴입니다."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"왼쪽으로 이동"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"오른쪽으로 이동"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"위로 이동"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"아래로 이동"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"완료"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings_tv.xml b/libs/WindowManager/Shell/res/values-ky/strings_tv.xml
index 887ac52c8e43..19fac5876bb0 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Сүрөттөгү сүрөт"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Аталышы жок программа)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP\'ти жабуу"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Жабуу"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Толук экран"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP\'ти жылдыруу"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIP\'ти жайып көрсөтүү"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIP\'ти жыйыштыруу"</string>
+ <string name="pip_move" msgid="158770205886688553">"Жылдыруу"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Жайып көрсөтүү"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Жыйыштыруу"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Башкаруу элементтерин ачуу үчүн "<annotation icon="home_icon">" БАШКЫ БЕТ "</annotation>" баскычын эки жолу басыңыз"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Сүрөт ичиндеги сүрөт менюсу."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Солго жылдыруу"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Оңго жылдыруу"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Жогору жылдыруу"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Төмөн жылдыруу"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Бүттү"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings_tv.xml b/libs/WindowManager/Shell/res/values-lo/strings_tv.xml
index 91c4a033356d..6cd0f37c516c 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ການສະແດງຜົນຊ້ອນກັນ"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ໂປຣແກຣມບໍ່ມີຊື່)"</string>
- <string name="pip_close" msgid="9135220303720555525">"ປິດ PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"ປິດ"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"ເຕັມໜ້າຈໍ"</string>
- <string name="pip_move" msgid="1544227837964635439">"ຍ້າຍ PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"ຂະຫຍາຍ PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"ຫຍໍ້ PIP ລົງ"</string>
+ <string name="pip_move" msgid="158770205886688553">"ຍ້າຍ"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"ຂະຫຍາຍ"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"ຫຍໍ້"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" ກົດ "<annotation icon="home_icon">" HOME "</annotation>" ສອງເທື່ອສຳລັບການຄວບຄຸມ"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"ເມນູການສະແດງຜົນຊ້ອນກັນ."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ຍ້າຍໄປຊ້າຍ"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"ຍ້າຍໄປຂວາ"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ຍ້າຍຂຶ້ນ"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"ຍ້າຍລົງ"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"ແລ້ວໆ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings_tv.xml b/libs/WindowManager/Shell/res/values-lt/strings_tv.xml
index 04265ca01b48..52017dca2b94 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Vaizdas vaizde"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programa be pavadinimo)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Uždaryti PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Uždaryti"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Visas ekranas"</string>
- <string name="pip_move" msgid="1544227837964635439">"Perkelti PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Iškleisti PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Sutraukti PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Perkelti"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Išskleisti"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Sutraukti"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Jei reikia valdiklių, dukart paspauskite "<annotation icon="home_icon">"PAGRINDINIS"</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Vaizdo vaizde meniu."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Perkelti kairėn"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Perkelti dešinėn"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Perkelti aukštyn"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Perkelti žemyn"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Atlikta"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings_tv.xml b/libs/WindowManager/Shell/res/values-lv/strings_tv.xml
index 8c6191e00833..11abac6f6197 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Attēls attēlā"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programma bez nosaukuma)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Aizvērt PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Aizvērt"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Pilnekrāna režīms"</string>
- <string name="pip_move" msgid="1544227837964635439">"Pārvietot attēlu attēlā"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Izvērst “Attēls attēlā” logu"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Sakļaut “Attēls attēlā” logu"</string>
+ <string name="pip_move" msgid="158770205886688553">"Pārvietot"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Izvērst"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Sakļaut"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Atvērt vadīklas: divreiz nospiediet pogu "<annotation icon="home_icon">"SĀKUMS"</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Izvēlne attēlam attēlā."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Pārvietot pa kreisi"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Pārvietot pa labi"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Pārvietot augšup"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Pārvietot lejup"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Gatavs"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings_tv.xml b/libs/WindowManager/Shell/res/values-mk/strings_tv.xml
index beef1fef862b..21293223b882 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Слика во слика"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Програма без наслов)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Затвори PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Затвори"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Цел екран"</string>
- <string name="pip_move" msgid="1544227837964635439">"Премести PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Прошири ја сликата во слика"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Собери ја сликата во слика"</string>
+ <string name="pip_move" msgid="158770205886688553">"Премести"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Прошири"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Собери"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Притиснете двапати на "<annotation icon="home_icon">" HOME "</annotation>" за контроли"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Мени за „Слика во слика“."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Премести налево"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Премести надесно"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Премести нагоре"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Премести надолу"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Готово"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings_tv.xml b/libs/WindowManager/Shell/res/values-ml/strings_tv.xml
index c2a532d09647..549e39b21101 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ചിത്രത്തിനുള്ളിൽ ചിത്രം"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(പേരില്ലാത്ത പ്രോഗ്രാം)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP അടയ്ക്കുക"</string>
+ <string name="pip_close" msgid="2955969519031223530">"അടയ്ക്കുക"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"പൂര്‍ണ്ണ സ്ക്രീന്‍"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP നീക്കുക"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIP വികസിപ്പിക്കുക"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIP ചുരുക്കുക"</string>
+ <string name="pip_move" msgid="158770205886688553">"നീക്കുക"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"വികസിപ്പിക്കുക"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"ചുരുക്കുക"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" നിയന്ത്രണങ്ങൾക്കായി "<annotation icon="home_icon">" ഹോം "</annotation>" രണ്ട് തവണ അമർത്തുക"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"ചിത്രത്തിനുള്ളിൽ ചിത്രം മെനു."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ഇടത്തേക്ക് നീക്കുക"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"വലത്തേക്ക് നീക്കുക"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"മുകളിലേക്ക് നീക്കുക"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"താഴേക്ക് നീക്കുക"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"പൂർത്തിയായി"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings_tv.xml b/libs/WindowManager/Shell/res/values-mn/strings_tv.xml
index bf8c59b57359..9a85d96ca602 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Дэлгэц доторх дэлгэц"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Гарчиггүй хөтөлбөр)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP-г хаах"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Хаах"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Бүтэн дэлгэц"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP-г зөөх"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIP-г дэлгэх"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIP-г хураах"</string>
+ <string name="pip_move" msgid="158770205886688553">"Зөөх"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Дэлгэх"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Хураах"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Хяналтад хандах бол "<annotation icon="home_icon">" HOME "</annotation>" дээр хоёр дарна уу"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Дэлгэцэн доторх дэлгэцийн цэс."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Зүүн тийш зөөх"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Баруун тийш зөөх"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Дээш зөөх"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Доош зөөх"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Болсон"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings_tv.xml b/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
index 5d519b7afe9a..a9779b3a3e89 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"चित्रात-चित्र"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(शीर्षक नसलेला कार्यक्रम)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP बंद करा"</string>
+ <string name="pip_close" msgid="2955969519031223530">"बंद करा"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"फुल स्क्रीन"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP हलवा"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIP चा विस्तार करा"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIP कोलॅप्स करा"</string>
+ <string name="pip_move" msgid="158770205886688553">"हलवा"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"विस्तार करा"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"कोलॅप्स करा"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" नियंत्रणांसाठी "<annotation icon="home_icon">" होम "</annotation>" दोनदा दाबा"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"चित्रात-चित्र मेनू."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"डावीकडे हलवा"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"उजवीकडे हलवा"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"वर हलवा"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"खाली हलवा"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"पूर्ण झाले"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings_tv.xml b/libs/WindowManager/Shell/res/values-ms/strings_tv.xml
index 08642c47c91a..8fe992d9f3b9 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Gambar dalam Gambar"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program tiada tajuk)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Tutup PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Tutup"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Skrin penuh"</string>
- <string name="pip_move" msgid="1544227837964635439">"Alihkan PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Kembangkan PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Kuncupkan PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Alih"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Kembangkan"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Kuncupkan"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Tekan dua kali "<annotation icon="home_icon">" LAMAN UTAMA "</annotation>" untuk mengakses kawalan"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu Gambar dalam Gambar."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Alih ke kiri"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Alih ke kanan"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Alih ke atas"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Alih ke bawah"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Selesai"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-my/strings_tv.xml b/libs/WindowManager/Shell/res/values-my/strings_tv.xml
index e01daee115ca..105628d8149e 100644
--- a/libs/WindowManager/Shell/res/values-my/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"နှစ်ခုထပ်၍ကြည့်ခြင်း"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ခေါင်းစဉ်မဲ့ အစီအစဉ်)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP ကိုပိတ်ပါ"</string>
+ <string name="pip_close" msgid="2955969519031223530">"ပိတ်ရန်"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"မျက်နှာပြင် အပြည့်"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP ရွှေ့ရန်"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIP ကို ချဲ့ရန်"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIP ကို လျှော့ပြပါ"</string>
+ <string name="pip_move" msgid="158770205886688553">"ရွှေ့ရန်"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"ချဲ့ရန်"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"လျှော့ပြရန်"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" ထိန်းချုပ်မှုအတွက် "<annotation icon="home_icon">" ပင်မခလုတ် "</annotation>" နှစ်ချက်နှိပ်ပါ"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"နှစ်ခုထပ်၍ ကြည့်ခြင်းမီနူး။"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ဘယ်သို့ရွှေ့ရန်"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"ညာသို့ရွှေ့ရန်"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"အပေါ်သို့ရွှေ့ရန်"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"အောက်သို့ရွှေ့ရန်"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"ပြီးပြီ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings_tv.xml b/libs/WindowManager/Shell/res/values-nb/strings_tv.xml
index 65ed0b7f5bff..ca63518df7a5 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Bilde-i-bilde"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program uten tittel)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Lukk PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Lukk"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Fullskjerm"</string>
- <string name="pip_move" msgid="1544227837964635439">"Flytt BIB"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Vis BIB"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Skjul BIB"</string>
+ <string name="pip_move" msgid="158770205886688553">"Flytt"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Vis"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Skjul"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Dobbelttrykk på "<annotation icon="home_icon">"HJEM"</annotation>" for å åpne kontroller"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Bilde-i-bilde-meny."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Flytt til venstre"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Flytt til høyre"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Flytt opp"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Flytt ned"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Ferdig"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings_tv.xml b/libs/WindowManager/Shell/res/values-ne/strings_tv.xml
index d33fed67efb6..7cbf9e294e7b 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-Picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(शीर्षकविहीन कार्यक्रम)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP लाई बन्द गर्नुहोस्"</string>
+ <string name="pip_close" msgid="2955969519031223530">"बन्द गर्नुहोस्"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"फुल स्क्रिन"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP सार्नुहोस्"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIP विन्डो एक्स्पान्ड गर्नु…"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIP विन्डो कोल्याप्स गर्नुहोस्"</string>
+ <string name="pip_move" msgid="158770205886688553">"सार्नुहोस्"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"एक्स्पान्ड गर्नुहोस्"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"कोल्याप्स गर्नुहोस्"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" कन्ट्रोल मेनु खोल्न "<annotation icon="home_icon">" होम "</annotation>" बटन दुई पटक थिच्नुहोस्"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"\"picture-in-picture\" मेनु।"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"बायाँतिर सार्नुहोस्"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"दायाँतिर सार्नुहोस्"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"माथितिर सार्नुहोस्"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"तलतिर सार्नुहोस्"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"सम्पन्न भयो"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings_tv.xml b/libs/WindowManager/Shell/res/values-nl/strings_tv.xml
index 9763c5665ab2..2deaeddc4080 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Scherm-in-scherm"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Naamloos programma)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP sluiten"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Sluiten"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Volledig scherm"</string>
- <string name="pip_move" msgid="1544227837964635439">"SIS verplaatsen"</string>
- <string name="pip_expand" msgid="7605396312689038178">"SIS uitvouwen"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"SIS samenvouwen"</string>
+ <string name="pip_move" msgid="158770205886688553">"Verplaatsen"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Uitvouwen"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Samenvouwen"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Druk twee keer op "<annotation icon="home_icon">" HOME "</annotation>" voor bedieningselementen"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Scherm-in-scherm-menu."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Naar links verplaatsen"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Naar rechts verplaatsen"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Omhoog verplaatsen"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Omlaag verplaatsen"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Klaar"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-or/strings_tv.xml b/libs/WindowManager/Shell/res/values-or/strings_tv.xml
index e0344855bd1f..0c1d99e4ca71 100644
--- a/libs/WindowManager/Shell/res/values-or/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ପିକଚର୍-ଇନ୍-ପିକଚର୍"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(କୌଣସି ଟାଇଟଲ୍‍ ପ୍ରୋଗ୍ରାମ୍‍ ନାହିଁ)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="pip_close" msgid="2955969519031223530">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍‍"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIPକୁ ମୁଭ କରନ୍ତୁ"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIPକୁ ବିସ୍ତାର କରନ୍ତୁ"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIPକୁ ସଙ୍କୁଚିତ କରନ୍ତୁ"</string>
+ <string name="pip_move" msgid="158770205886688553">"ମୁଭ କରନ୍ତୁ"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"ବିସ୍ତାର କରନ୍ତୁ"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"ସଙ୍କୁଚିତ କରନ୍ତୁ"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ପାଇଁ "<annotation icon="home_icon">" ହୋମ ବଟନ "</annotation>"କୁ ଦୁଇଥର ଦବାନ୍ତୁ"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"ପିକଚର-ଇନ-ପିକଚର ମେନୁ।"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ବାମକୁ ମୁଭ କରନ୍ତୁ"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"ଡାହାଣକୁ ମୁଭ କରନ୍ତୁ"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ଉପରକୁ ମୁଭ କରନ୍ତୁ"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"ତଳକୁ ମୁଭ କରନ୍ତୁ"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"ହୋଇଗଲା"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings_tv.xml b/libs/WindowManager/Shell/res/values-pa/strings_tv.xml
index 9c01ac3f3cc0..a1edde738775 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"ਤਸਵੀਰ-ਵਿੱਚ-ਤਸਵੀਰ"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ਸਿਰਲੇਖ-ਰਹਿਤ ਪ੍ਰੋਗਰਾਮ)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP ਬੰਦ ਕਰੋ"</string>
+ <string name="pip_close" msgid="2955969519031223530">"ਬੰਦ ਕਰੋ"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"ਪੂਰੀ ਸਕ੍ਰੀਨ"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP ਨੂੰ ਲਿਜਾਓ"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIP ਦਾ ਵਿਸਤਾਰ ਕਰੋ"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIP ਨੂੰ ਸਮੇਟੋ"</string>
+ <string name="pip_move" msgid="158770205886688553">"ਲਿਜਾਓ"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"ਵਿਸਤਾਰ ਕਰੋ"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"ਸਮੇਟੋ"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" ਕੰਟਰੋਲਾਂ ਲਈ "<annotation icon="home_icon">" ਹੋਮ ਬਟਨ "</annotation>" ਨੂੰ ਦੋ ਵਾਰ ਦਬਾਓ"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"ਤਸਵੀਰ-ਵਿੱਚ-ਤਸਵੀਰ ਮੀਨੂ।"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ਖੱਬੇ ਲਿਜਾਓ"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"ਸੱਜੇ ਲਿਜਾਓ"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ਉੱਪਰ ਲਿਜਾਓ"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"ਹੇਠਾਂ ਲਿਜਾਓ"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"ਹੋ ਗਿਆ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings_tv.xml b/libs/WindowManager/Shell/res/values-pl/strings_tv.xml
index b922e2d5a6ba..2bb90addc241 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Obraz w obrazie"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program bez tytułu)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Zamknij PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Zamknij"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Pełny ekran"</string>
- <string name="pip_move" msgid="1544227837964635439">"Przenieś PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Rozwiń PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Zwiń PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Przenieś"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Rozwiń"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Zwiń"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Naciśnij dwukrotnie "<annotation icon="home_icon">"EKRAN GŁÓWNY"</annotation>", aby wyświetlić ustawienia"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu funkcji Obraz w obrazie."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Przenieś w lewo"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Przenieś w prawo"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Przenieś w górę"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Przenieś w dół"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Gotowe"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml
index cc4eb3c32c1f..14d1c34fd3e8 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(programa sem título)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Fechar PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Fechar"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Tela cheia"</string>
- <string name="pip_move" msgid="1544227837964635439">"Mover picture-in-picture"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Abrir picture-in-picture"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Fechar picture-in-picture"</string>
+ <string name="pip_move" msgid="158770205886688553">"Mover"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Abrir"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Fechar"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Pressione o botão "<annotation icon="home_icon">"home"</annotation>" duas vezes para acessar os controles"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu do picture-in-picture"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mover para a esquerda"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mover para a direita"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mover para cima"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Mover para baixo"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Concluído"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml
index c4ae78d89ba8..1ada4508714a 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Ecrã no ecrã"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Sem título do programa)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Fechar PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Fechar"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Ecrã inteiro"</string>
- <string name="pip_move" msgid="1544227837964635439">"Mover Ecrã no ecrã"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Expandir Ecrã no ecrã"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Reduzir Ecrã no ecrã"</string>
+ <string name="pip_move" msgid="158770205886688553">"Mover"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Expandir"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Reduzir"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Prima duas vezes "<annotation icon="home_icon">" PÁGINA INICIAL "</annotation>" para controlos"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu de ecrã no ecrã."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mover para a esquerda"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mover para a direita"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mover para cima"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Mover para baixo"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Concluído"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings_tv.xml b/libs/WindowManager/Shell/res/values-pt/strings_tv.xml
index cc4eb3c32c1f..14d1c34fd3e8 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(programa sem título)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Fechar PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Fechar"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Tela cheia"</string>
- <string name="pip_move" msgid="1544227837964635439">"Mover picture-in-picture"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Abrir picture-in-picture"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Fechar picture-in-picture"</string>
+ <string name="pip_move" msgid="158770205886688553">"Mover"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Abrir"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Fechar"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Pressione o botão "<annotation icon="home_icon">"home"</annotation>" duas vezes para acessar os controles"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu do picture-in-picture"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mover para a esquerda"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mover para a direita"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mover para cima"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Mover para baixo"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Concluído"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings_tv.xml b/libs/WindowManager/Shell/res/values-ro/strings_tv.xml
index 86a30f49df15..56dadb2e5e65 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program fără titlu)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Închideți PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Închideți"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Ecran complet"</string>
- <string name="pip_move" msgid="1544227837964635439">"Mutați fereastra PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Extindeți fereastra PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Restrângeți fereastra PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Mutați"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Extindeți"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Restrângeți"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Apăsați de două ori "<annotation icon="home_icon">"butonul ecran de pornire"</annotation>" pentru comenzi"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Meniu picture-in-picture."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mutați spre stânga"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mutați spre dreapta"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mutați în sus"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Mutați în jos"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Gata"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings_tv.xml b/libs/WindowManager/Shell/res/values-ru/strings_tv.xml
index 08623e1e69c5..e7f55ec1bc57 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Картинка в картинке"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Без названия)"</string>
- <string name="pip_close" msgid="9135220303720555525">"\"Кадр в кадре\" – выйти"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Закрыть"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Во весь экран"</string>
- <string name="pip_move" msgid="1544227837964635439">"Переместить PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Развернуть PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Свернуть PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Переместить"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Развернуть"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Свернуть"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Элементы управления: дважды нажмите "<annotation icon="home_icon">" кнопку главного экрана "</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Меню \"Картинка в картинке\"."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Переместить влево"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Переместить вправо"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Переместить вверх"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Переместить вниз"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Готово"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-si/strings_tv.xml b/libs/WindowManager/Shell/res/values-si/strings_tv.xml
index fbb0ebba0623..5478ce5d3d40 100644
--- a/libs/WindowManager/Shell/res/values-si/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"පින්තූරය-තුළ-පින්තූරය"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(මාතෘකාවක් නැති වැඩසටහන)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP වසන්න"</string>
+ <string name="pip_close" msgid="2955969519031223530">"වසන්න"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"සම්පූර්ණ තිරය"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP ගෙන යන්න"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIP දිග හරින්න"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIP හකුළන්න"</string>
+ <string name="pip_move" msgid="158770205886688553">"ගෙන යන්න"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"දිග හරින්න"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"හකුළන්න"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" පාලන සඳහා "<annotation icon="home_icon">" මුල් පිටුව "</annotation>" දෙවරක් ඔබන්න"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"පින්තූරය තුළ පින්තූරය මෙනුව"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"වමට ගෙන යන්න"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"දකුණට ගෙන යන්න"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ඉහළට ගෙන යන්න"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"පහළට ගෙන යන්න"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"නිමයි"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings_tv.xml b/libs/WindowManager/Shell/res/values-sk/strings_tv.xml
index 81cb0eafc759..1df43afca2da 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Obraz v obraze"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program bez názvu)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Zavrieť režim PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Zavrieť"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Celá obrazovka"</string>
- <string name="pip_move" msgid="1544227837964635439">"Presunúť obraz v obraze"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Rozbaliť obraz v obraze"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Zbaliť obraz v obraze"</string>
+ <string name="pip_move" msgid="158770205886688553">"Presunúť"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Rozbaliť"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Zbaliť"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Ovládanie zobraz. dvoj. stlač. "<annotation icon="home_icon">" TLAČIDLA PLOCHY "</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Ponuka obrazu v obraze."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Posunúť doľava"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Posunúť doprava"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Posunúť nahor"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Posunúť nadol"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Hotovo"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings_tv.xml b/libs/WindowManager/Shell/res/values-sl/strings_tv.xml
index 060aaa0ce647..88fc8325aa01 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Slika v sliki"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program brez naslova)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Zapri način PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Zapri"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Celozaslonsko"</string>
- <string name="pip_move" msgid="1544227837964635439">"Premakni sliko v sliki"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Razširi sliko v sliki"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Strni sliko v sliki"</string>
+ <string name="pip_move" msgid="158770205886688553">"Premakni"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Razširi"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Strni"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Za kontrolnike dvakrat pritisnite gumb za "<annotation icon="home_icon">" ZAČETNI ZASLON "</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Meni za sliko v sliki"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Premakni levo"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Premakni desno"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Premakni navzgor"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Premakni navzdol"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Končano"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings_tv.xml b/libs/WindowManager/Shell/res/values-sq/strings_tv.xml
index 9bfdb6a3edd8..58687e5867fe 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Figurë brenda figurës"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program pa titull)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Mbyll PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Mbyll"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Ekrani i plotë"</string>
- <string name="pip_move" msgid="1544227837964635439">"Zhvendos PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Zgjero PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Palos PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Lëviz"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Zgjero"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Palos"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Trokit dy herë "<annotation icon="home_icon">" KREU "</annotation>" për kontrollet"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menyja e \"Figurës brenda figurës\"."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Lëviz majtas"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Lëviz djathtas"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Lëviz lart"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Lëviz poshtë"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"U krye"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings_tv.xml b/libs/WindowManager/Shell/res/values-sr/strings_tv.xml
index 6bc5c87bab48..e850979174a3 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Слика у слици"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Програм без наслова)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Затвори PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Затвори"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Цео екран"</string>
- <string name="pip_move" msgid="1544227837964635439">"Премести слику у слици"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Прошири слику у слици"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Скупи слику у слици"</string>
+ <string name="pip_move" msgid="158770205886688553">"Премести"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Прошири"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Скупи"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Двапут притисните "<annotation icon="home_icon">" HOME "</annotation>" за контроле"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Мени Слика у слици."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Померите налево"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Померите надесно"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Померите нагоре"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Померите надоле"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Готово"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings_tv.xml b/libs/WindowManager/Shell/res/values-sv/strings_tv.xml
index b3465ab1db85..d3a9c3de66db 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Bild-i-bild"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Namnlöst program)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Stäng PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Stäng"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Helskärm"</string>
- <string name="pip_move" msgid="1544227837964635439">"Flytta BIB"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Utöka bild-i-bild"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Komprimera bild-i-bild"</string>
+ <string name="pip_move" msgid="158770205886688553">"Flytta"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Utöka"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Komprimera"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Tryck snabbt två gånger på "<annotation icon="home_icon">" HEM "</annotation>" för kontroller"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Bild-i-bild-meny."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Flytta åt vänster"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Flytta åt höger"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Flytta uppåt"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Flytta nedåt"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Klar"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings_tv.xml b/libs/WindowManager/Shell/res/values-sw/strings_tv.xml
index baff49ed821a..7b9a310ff0b6 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Pachika Picha Ndani ya Picha Nyingine"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programu isiyo na jina)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Funga PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Funga"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Skrini nzima"</string>
- <string name="pip_move" msgid="1544227837964635439">"Kuhamisha PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Panua PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Kunja PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Hamisha"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Panua"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Kunja"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Bonyeza mara mbili kitufe cha "<annotation icon="home_icon">" UKURASA WA KWANZA "</annotation>" kupata vidhibiti"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menyu ya kipengele cha kupachika picha ndani ya picha nyingine."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Sogeza kushoto"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Sogeza kulia"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Sogeza juu"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Sogeza chini"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Imemaliza"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings_tv.xml b/libs/WindowManager/Shell/res/values-ta/strings_tv.xml
index 4439e299c919..e201401e2e35 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"பிக்ச்சர்-இன்-பிக்ச்சர்"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(தலைப்பு இல்லை)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIPஐ மூடு"</string>
+ <string name="pip_close" msgid="2955969519031223530">"மூடுக"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"முழுத்திரை"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIPபை நகர்த்து"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIPபை விரிவாக்கு"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIPபைச் சுருக்கு"</string>
+ <string name="pip_move" msgid="158770205886688553">"நகர்த்து"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"விரி"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"சுருக்கு"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" கட்டுப்பாடுகள்: "<annotation icon="home_icon">" முகப்பு "</annotation>" பட்டனை இருமுறை அழுத்துக"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"பிக்ச்சர்-இன்-பிக்ச்சர் மெனு."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"இடப்புறம் நகர்த்து"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"வலப்புறம் நகர்த்து"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"மேலே நகர்த்து"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"கீழே நகர்த்து"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"முடிந்தது"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-te/strings_tv.xml b/libs/WindowManager/Shell/res/values-te/strings_tv.xml
index 35579346615f..6284d90cb11f 100644
--- a/libs/WindowManager/Shell/res/values-te/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"పిక్చర్-ఇన్-పిక్చర్"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(శీర్షిక లేని ప్రోగ్రామ్)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIPని మూసివేయి"</string>
+ <string name="pip_close" msgid="2955969519031223530">"మూసివేయండి"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"ఫుల్-స్క్రీన్‌"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIPను తరలించండి"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIPని విస్తరించండి"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIPని కుదించండి"</string>
+ <string name="pip_move" msgid="158770205886688553">"తరలించండి"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"విస్తరించండి"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"కుదించండి"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" కంట్రోల్స్ కోసం "<annotation icon="home_icon">" HOME "</annotation>" బటన్ రెండుసార్లు నొక్కండి"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"పిక్చర్-ఇన్-పిక్చర్ మెనూ."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ఎడమ వైపుగా జరపండి"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"కుడి వైపుగా జరపండి"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"పైకి జరపండి"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"కిందికి జరపండి"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"పూర్తయింది"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-th/strings_tv.xml b/libs/WindowManager/Shell/res/values-th/strings_tv.xml
index 0a07d157ec6f..27cf56c6e154 100644
--- a/libs/WindowManager/Shell/res/values-th/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"การแสดงภาพซ้อนภาพ"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ไม่มีชื่อรายการ)"</string>
- <string name="pip_close" msgid="9135220303720555525">"ปิด PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"ปิด"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"เต็มหน้าจอ"</string>
- <string name="pip_move" msgid="1544227837964635439">"ย้าย PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"ขยาย PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"ยุบ PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"ย้าย"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"ขยาย"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"ยุบ"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" กดปุ่ม "<annotation icon="home_icon">" หน้าแรก "</annotation>" สองครั้งเพื่อเปิดการควบคุม"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"เมนูการแสดงภาพซ้อนภาพ"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"ย้ายไปทางซ้าย"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"ย้ายไปทางขวา"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"ย้ายขึ้น"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"ย้ายลง"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"เสร็จ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings_tv.xml b/libs/WindowManager/Shell/res/values-tl/strings_tv.xml
index 9a11a38fa492..4cc050bebe5b 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Picture-in-Picture"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Walang pamagat na programa)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Isara ang PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Isara"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Full screen"</string>
- <string name="pip_move" msgid="1544227837964635439">"Ilipat ang PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"I-expand ang PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"I-collapse ang PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Ilipat"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"I-expand"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"I-collapse"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" I-double press ang "<annotation icon="home_icon">" HOME "</annotation>" para sa mga kontrol"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menu ng Picture-in-Picture."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Ilipat pakaliwa"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Ilipat pakanan"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Itaas"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Ibaba"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Tapos na"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings_tv.xml b/libs/WindowManager/Shell/res/values-tr/strings_tv.xml
index bf4bc6f1fff7..69bb608061e4 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Pencere İçinde Pencere"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Başlıksız program)"</string>
- <string name="pip_close" msgid="9135220303720555525">"PIP\'yi kapat"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Kapat"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Tam ekran"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIP\'yi taşı"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIP penceresini genişlet"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIP penceresini daralt"</string>
- <string name="pip_edu_text" msgid="3672999496647508701">" Kontroller için "<annotation icon="home_icon">" ANA SAYFA "</annotation>"\'ya iki kez basın"</string>
+ <string name="pip_move" msgid="158770205886688553">"Taşı"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Genişlet"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Daralt"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Kontroller için "<annotation icon="home_icon">" ANA SAYFA "</annotation>" düğmesine iki kez basın"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Pencere içinde pencere menüsü."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Sola taşı"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Sağa taşı"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Yukarı taşı"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Aşağı taşı"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Bitti"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings_tv.xml b/libs/WindowManager/Shell/res/values-uk/strings_tv.xml
index 7e9f54e68f54..81a8285c58cf 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Картинка в картинці"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Програма без назви)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Закрити PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Закрити"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"На весь екран"</string>
- <string name="pip_move" msgid="1544227837964635439">"Перемістити картинку в картинці"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Розгорнути картинку в картинці"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Згорнути картинку в картинці"</string>
+ <string name="pip_move" msgid="158770205886688553">"Перемістити"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Розгорнути"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Згорнути"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Відкрити елементи керування: двічі натисніть "<annotation icon="home_icon">"HOME"</annotation></string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Меню \"картинка в картинці\""</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Перемістити ліворуч"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Перемістити праворуч"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Перемістити вгору"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Перемістити вниз"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Готово"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings_tv.xml b/libs/WindowManager/Shell/res/values-ur/strings_tv.xml
index c2ef69ff1488..e83885772f2d 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"تصویر میں تصویر"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(بلا عنوان پروگرام)"</string>
- <string name="pip_close" msgid="9135220303720555525">"‏PIP بند کریں"</string>
+ <string name="pip_close" msgid="2955969519031223530">"بند کریں"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"فُل اسکرین"</string>
- <string name="pip_move" msgid="1544227837964635439">"‏PIP کو منتقل کریں"</string>
- <string name="pip_expand" msgid="7605396312689038178">"‏PIP کو پھیلائیں"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"‏PIP کو سکیڑیں"</string>
+ <string name="pip_move" msgid="158770205886688553">"منتقل کریں"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"پھیلائیں"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"سکیڑیں"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" کنٹرولز کے لیے "<annotation icon="home_icon">"ہوم "</annotation>" بٹن کو دو بار دبائیں"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"تصویر میں تصویر کا مینو۔"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"دائیں منتقل کریں"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"بائیں منتقل کریں"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"اوپر منتقل کریں"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"نیچے منتقل کریں"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"ہو گیا"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings_tv.xml b/libs/WindowManager/Shell/res/values-uz/strings_tv.xml
index 9ab95c80aa25..da953356628c 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Tasvir ustida tasvir"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Nomsiz)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Kadr ichida kadr – chiqish"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Yopish"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Butun ekran"</string>
- <string name="pip_move" msgid="1544227837964635439">"PIPni siljitish"</string>
- <string name="pip_expand" msgid="7605396312689038178">"PIP funksiyasini yoyish"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"PIP funksiyasini yopish"</string>
+ <string name="pip_move" msgid="158770205886688553">"Boshqa joyga olish"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Yoyish"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Yopish"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Boshqaruv uchun "<annotation icon="home_icon">"ASOSIY"</annotation>" tugmani ikki marta bosing"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Tasvir ustida tasvir menyusi."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Chapga olish"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Oʻngga olish"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Tepaga olish"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Pastga olish"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Tayyor"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings_tv.xml b/libs/WindowManager/Shell/res/values-vi/strings_tv.xml
index 146376d3cab6..1f9260fdcff0 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Hình trong hình"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Không có chương trình tiêu đề)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Đóng PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Đóng"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Toàn màn hình"</string>
- <string name="pip_move" msgid="1544227837964635439">"Di chuyển PIP (Ảnh trong ảnh)"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Mở rộng PIP (Ảnh trong ảnh)"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Thu gọn PIP (Ảnh trong ảnh)"</string>
+ <string name="pip_move" msgid="158770205886688553">"Di chuyển"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Mở rộng"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Thu gọn"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Nhấn đúp vào nút "<annotation icon="home_icon">" MÀN HÌNH CHÍNH "</annotation>" để mở trình đơn điều khiển"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Trình đơn hình trong hình."</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Di chuyển sang trái"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Di chuyển sang phải"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Di chuyển lên"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Di chuyển xuống"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Xong"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml
index 55407d2c699d..399d639fe70f 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"画中画"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(节目没有标题)"</string>
- <string name="pip_close" msgid="9135220303720555525">"关闭画中画"</string>
+ <string name="pip_close" msgid="2955969519031223530">"关闭"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"全屏"</string>
- <string name="pip_move" msgid="1544227837964635439">"移动画中画窗口"</string>
- <string name="pip_expand" msgid="7605396312689038178">"展开 PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"收起 PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"移动"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"展开"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"收起"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" 按两次"<annotation icon="home_icon">"主屏幕"</annotation>"按钮可查看相关控件"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"画中画菜单。"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"左移"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"右移"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"上移"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"下移"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"完成"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml
index 15e278d8ecc2..acbc26d033cd 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"畫中畫"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(沒有標題的節目)"</string>
- <string name="pip_close" msgid="9135220303720555525">"關閉 PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"關閉"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"全螢幕"</string>
- <string name="pip_move" msgid="1544227837964635439">"移動畫中畫"</string>
- <string name="pip_expand" msgid="7605396312689038178">"展開畫中畫"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"收合畫中畫"</string>
+ <string name="pip_move" msgid="158770205886688553">"移動"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"展開"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"收合"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" 按兩下"<annotation icon="home_icon">" 主畫面按鈕"</annotation>"即可顯示控制項"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"畫中畫選單。"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"向左移"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"向右移"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"向上移"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"向下移"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"完成"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml
index 0b17b31d23d0..f8c683ec3a60 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"子母畫面"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(無標題的節目)"</string>
- <string name="pip_close" msgid="9135220303720555525">"關閉子母畫面"</string>
+ <string name="pip_close" msgid="2955969519031223530">"關閉"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"全螢幕"</string>
- <string name="pip_move" msgid="1544227837964635439">"移動子母畫面"</string>
- <string name="pip_expand" msgid="7605396312689038178">"展開子母畫面"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"收合子母畫面"</string>
+ <string name="pip_move" msgid="158770205886688553">"移動"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"展開"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"收合"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" 按兩下"<annotation icon="home_icon">"主畫面按鈕"</annotation>"即可顯示控制選項"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"子母畫面選單。"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"向左移動"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"向右移動"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"向上移動"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"向下移動"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"完成"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings_tv.xml b/libs/WindowManager/Shell/res/values-zu/strings_tv.xml
index dad8c8128222..20243a9dfc9c 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings_tv.xml
@@ -19,10 +19,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="2576686079160402435">"Isithombe-esithombeni"</string>
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Alukho uhlelo lwesihloko)"</string>
- <string name="pip_close" msgid="9135220303720555525">"Vala i-PIP"</string>
+ <string name="pip_close" msgid="2955969519031223530">"Vala"</string>
<string name="pip_fullscreen" msgid="7278047353591302554">"Iskrini esigcwele"</string>
- <string name="pip_move" msgid="1544227837964635439">"Hambisa i-PIP"</string>
- <string name="pip_expand" msgid="7605396312689038178">"Nweba i-PIP"</string>
- <string name="pip_collapse" msgid="5732233773786896094">"Goqa i-PIP"</string>
+ <string name="pip_move" msgid="158770205886688553">"Hambisa"</string>
+ <string name="pip_expand" msgid="1051966011679297308">"Nweba"</string>
+ <string name="pip_collapse" msgid="3903295106641385962">"Goqa"</string>
<string name="pip_edu_text" msgid="3672999496647508701">" Chofoza kabili "<annotation icon="home_icon">" IKHAYA"</annotation>" mayelana nezilawuli"</string>
+ <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Imenyu yesithombe-esithombeni"</string>
+ <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Yisa kwesokunxele"</string>
+ <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Yisa kwesokudla"</string>
+ <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Khuphula"</string>
+ <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Yehlisa"</string>
+ <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Kwenziwe"</string>
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
index bf074b0337ef..9230c22c5d95 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
@@ -145,6 +145,8 @@ public class RootTaskDisplayAreaOrganizer extends DisplayAreaOrganizer {
}
mDisplayAreasInfo.remove(displayId);
+ mLeashes.get(displayId).release();
+ mLeashes.remove(displayId);
ArrayList<RootTaskDisplayAreaListener> listeners = mListeners.get(displayId);
if (listeners != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index bf8406c68a89..5df7b8a578d6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -908,6 +908,8 @@ public class BubbleExpandedView extends LinearLayout {
* @param animate whether the pointer should animate to this position.
*/
public void setPointerPosition(float bubblePosition, boolean onLeft, boolean animate) {
+ final boolean isRtl = mContext.getResources().getConfiguration().getLayoutDirection()
+ == LAYOUT_DIRECTION_RTL;
// Pointer gets drawn in the padding
final boolean showVertically = mPositioner.showBubblesVertically();
final float paddingLeft = (showVertically && onLeft)
@@ -932,12 +934,23 @@ public class BubbleExpandedView extends LinearLayout {
updatePointerView();
if (showVertically) {
mPointerPos.y = bubbleCenter - (mPointerWidth / 2f);
- mPointerPos.x = onLeft
- ? -mPointerHeight + mPointerOverlap
- : getWidth() - mPaddingRight - mPointerOverlap;
+ if (!isRtl) {
+ mPointerPos.x = onLeft
+ ? -mPointerHeight + mPointerOverlap
+ : getWidth() - mPaddingRight - mPointerOverlap;
+ } else {
+ mPointerPos.x = onLeft
+ ? -(getWidth() - mPaddingLeft - mPointerOverlap)
+ : mPointerHeight - mPointerOverlap;
+ }
} else {
mPointerPos.y = mPointerOverlap;
- mPointerPos.x = bubbleCenter - (mPointerWidth / 2f);
+ if (!isRtl) {
+ mPointerPos.x = bubbleCenter - (mPointerWidth / 2f);
+ } else {
+ mPointerPos.x = -(getWidth() - mPaddingLeft - bubbleCenter)
+ + (mPointerWidth / 2f);
+ }
}
if (animate) {
mPointerView.animate().translationX(mPointerPos.x).translationY(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 9770a3f8882c..dbad5df9cf56 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -16,6 +16,8 @@
package com.android.wm.shell.bubbles;
+import static android.view.View.LAYOUT_DIRECTION_RTL;
+
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
@@ -28,7 +30,6 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.util.Log;
import android.view.Surface;
-import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowMetrics;
@@ -565,16 +566,30 @@ public class BubblePositioner {
* @return the position of the bubble on-screen when the stack is expanded.
*/
public PointF getExpandedBubbleXY(int index, BubbleStackView.StackViewState state) {
- final float positionInRow = index * (mBubbleSize + mSpacingBetweenBubbles);
+ boolean showBubblesVertically = showBubblesVertically();
+ boolean isRtl = mContext.getResources().getConfiguration().getLayoutDirection()
+ == LAYOUT_DIRECTION_RTL;
+
+ int onScreenIndex;
+ if (showBubblesVertically || !isRtl) {
+ onScreenIndex = index;
+ } else {
+ // If bubbles are shown horizontally, check if RTL language is used.
+ // If RTL is active, position first bubble on the right and last on the left.
+ // Last bubble has screen index 0 and first bubble has max screen index value.
+ onScreenIndex = state.numberOfBubbles - 1 - index;
+ }
+
+ final float positionInRow = onScreenIndex * (mBubbleSize + mSpacingBetweenBubbles);
final float expandedStackSize = getExpandedStackSize(state.numberOfBubbles);
- final float centerPosition = showBubblesVertically()
+ final float centerPosition = showBubblesVertically
? mPositionRect.centerY()
: mPositionRect.centerX();
// alignment - centered on the edge
final float rowStart = centerPosition - (expandedStackSize / 2f);
float x;
float y;
- if (showBubblesVertically()) {
+ if (showBubblesVertically) {
int inset = mExpandedViewLargeScreenInsetClosestEdge;
y = rowStart + positionInRow;
int left = mIsLargeScreen
@@ -591,8 +606,8 @@ public class BubblePositioner {
x = rowStart + positionInRow;
}
- if (showBubblesVertically() && mImeVisible) {
- return new PointF(x, getExpandedBubbleYForIme(index, state));
+ if (showBubblesVertically && mImeVisible) {
+ return new PointF(x, getExpandedBubbleYForIme(onScreenIndex, state));
}
return new PointF(x, y);
}
@@ -701,7 +716,7 @@ public class BubblePositioner {
// Start on the left if we're in LTR, right otherwise.
final boolean startOnLeft =
mContext.getResources().getConfiguration().getLayoutDirection()
- != View.LAYOUT_DIRECTION_RTL;
+ != LAYOUT_DIRECTION_RTL;
final float startingVerticalOffset = mContext.getResources().getDimensionPixelOffset(
R.dimen.bubble_stack_starting_offset_y);
// TODO: placement bug here because mPositionRect doesn't handle the overhanging edge
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
index c24efb9f5534..b521cb6a3d38 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
@@ -16,6 +16,8 @@
package com.android.wm.shell.bubbles.animation;
+import static android.view.View.LAYOUT_DIRECTION_RTL;
+
import static com.android.wm.shell.bubbles.BubblePositioner.NUM_VISIBLE_WHEN_RESTING;
import static com.android.wm.shell.bubbles.BubbleStackView.HOME_GESTURE_ENABLED;
@@ -243,6 +245,11 @@ public class ExpandedAnimationController
};
}
+ boolean showBubblesVertically = mPositioner.showBubblesVertically();
+ final boolean isRtl =
+ mLayout.getContext().getResources().getConfiguration().getLayoutDirection()
+ == LAYOUT_DIRECTION_RTL;
+
// Animate each bubble individually, since each path will end in a different spot.
animationsForChildrenFromIndex(0, (index, animation) -> {
final View bubble = mLayout.getChildAt(index);
@@ -277,9 +284,20 @@ public class ExpandedAnimationController
// right side, the first bubble is traveling to the top left, so it leads. During
// collapse to the left, the first bubble has the shortest travel time back to the stack
// position, so it leads (and vice versa).
- final boolean firstBubbleLeads =
- (expanding && !mLayout.isFirstChildXLeftOfCenter(bubble.getTranslationX()))
+ final boolean firstBubbleLeads;
+ if (showBubblesVertically || !isRtl) {
+ firstBubbleLeads =
+ (expanding && !mLayout.isFirstChildXLeftOfCenter(bubble.getTranslationX()))
|| (!expanding && mLayout.isFirstChildXLeftOfCenter(mCollapsePoint.x));
+ } else {
+ // For RTL languages, when showing bubbles horizontally, it is reversed. The bubbles
+ // are positioned right to left. This means that when expanding from left, the top
+ // bubble will lead as it will be positioned on the right. And when expanding from
+ // right, the top bubble will have the least travel distance.
+ firstBubbleLeads =
+ (expanding && mLayout.isFirstChildXLeftOfCenter(bubble.getTranslationX()))
+ || (!expanding && !mLayout.isFirstChildXLeftOfCenter(mCollapsePoint.x));
+ }
final int startDelay = firstBubbleLeads
? (index * 10)
: ((mLayout.getChildCount() - index) * 10);
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 c5453d4394b8..47c9214bcae9 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
@@ -63,6 +63,7 @@ import com.android.wm.shell.pip.PipTransitionState;
import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.pip.phone.PhonePipMenuController;
import com.android.wm.shell.pip.phone.PipController;
+import com.android.wm.shell.pip.phone.PipKeepClearAlgorithm;
import com.android.wm.shell.pip.phone.PipMotionHelper;
import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.recents.RecentTasksController;
@@ -188,7 +189,8 @@ public class WMShellModule {
@Provides
static Optional<Pip> providePip(Context context, DisplayController displayController,
PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm,
- PipBoundsState pipBoundsState, PipMediaController pipMediaController,
+ PipKeepClearAlgorithm pipKeepClearAlgorithm, PipBoundsState pipBoundsState,
+ PipMotionHelper pipMotionHelper, PipMediaController pipMediaController,
PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer,
PipTouchHandler pipTouchHandler, PipTransitionController pipTransitionController,
WindowManagerShellWrapper windowManagerShellWrapper,
@@ -197,7 +199,8 @@ public class WMShellModule {
Optional<OneHandedController> oneHandedController,
@ShellMainThread ShellExecutor mainExecutor) {
return Optional.ofNullable(PipController.create(context, displayController,
- pipAppOpsListener, pipBoundsAlgorithm, pipBoundsState,
+ pipAppOpsListener, pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState,
+ pipMotionHelper,
pipMediaController, phonePipMenuController, pipTaskOrganizer,
pipTouchHandler, pipTransitionController, windowManagerShellWrapper,
taskStackListener, pipParamsChangedForwarder, oneHandedController, mainExecutor));
@@ -217,6 +220,12 @@ public class WMShellModule {
@WMSingleton
@Provides
+ static PipKeepClearAlgorithm providePipKeepClearAlgorithm() {
+ return new PipKeepClearAlgorithm();
+ }
+
+ @WMSingleton
+ @Provides
static PipBoundsAlgorithm providesPipBoundsAlgorithm(Context context,
PipBoundsState pipBoundsState, PipSnapAlgorithm pipSnapAlgorithm) {
return new PipBoundsAlgorithm(context, pipBoundsState, pipSnapAlgorithm);
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 22d1564cf2c4..4eba1697b595 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
@@ -25,6 +25,7 @@ import android.animation.Animator;
import android.animation.RectEvaluator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.app.TaskInfo;
import android.content.Context;
import android.graphics.Rect;
@@ -195,6 +196,15 @@ public class PipAnimationController {
}
/**
+ * Quietly cancel the animator by removing the listeners first.
+ */
+ static void quietCancel(@NonNull ValueAnimator animator) {
+ animator.removeAllUpdateListeners();
+ animator.removeAllListeners();
+ animator.cancel();
+ }
+
+ /**
* Additional callback interface for PiP animation
*/
public static class PipAnimationCallback {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
index a032b338aae8..0e32663955d3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
@@ -132,7 +132,8 @@ public abstract class PipContentOverlay {
tx.show(mLeash);
tx.setLayer(mLeash, Integer.MAX_VALUE);
tx.setBuffer(mLeash, mSnapshot.getHardwareBuffer());
- tx.setCrop(mLeash, mSourceRectHint);
+ // Relocate the content to parentLeash's coordinates.
+ tx.setPosition(mLeash, -mSourceRectHint.left, -mSourceRectHint.top);
tx.setScale(mLeash, mTaskSnapshotScaleX, mTaskSnapshotScaleY);
tx.reparent(mLeash, parentLeash);
tx.apply();
@@ -149,10 +150,11 @@ public abstract class PipContentOverlay {
// the atomicTx is committed along with the final WindowContainerTransaction.
final SurfaceControl.Transaction nonAtomicTx = new SurfaceControl.Transaction();
final float scaleX = (float) destinationBounds.width()
- / mSnapshot.getHardwareBuffer().getWidth();
+ / mSourceRectHint.width();
final float scaleY = (float) destinationBounds.height()
- / mSnapshot.getHardwareBuffer().getHeight();
- final float scale = Math.max(scaleX, scaleY);
+ / mSourceRectHint.height();
+ final float scale = Math.max(
+ scaleX * mTaskSnapshotScaleX, scaleY * mTaskSnapshotScaleY);
nonAtomicTx.setScale(mLeash, scale, scale);
nonAtomicTx.setPosition(mLeash,
-scale * mSourceRectHint.left / mTaskSnapshotScaleX,
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 c6e48f53681c..a017a2674359 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
@@ -105,8 +105,10 @@ public class PipSurfaceTransactionHelper {
SurfaceControl leash, Rect sourceRectHint,
Rect sourceBounds, Rect destinationBounds, Rect insets,
boolean isInPipDirection) {
- mTmpSourceRectF.set(sourceBounds);
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);
mTmpDestinationRect.inset(insets);
// Scale by the shortest edge and offset such that the top/left of the scaled inset source
// rect aligns with the top/left of the destination bounds
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 25a12e65110e..bd386b5681d8 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
@@ -461,6 +461,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
wct.setBoundsChangeTransaction(mToken, tx);
}
+ // Cancel the existing animator if there is any.
+ // TODO(b/232439933): this is disabled temporarily to unblock b/234502692.
+ // cancelCurrentAnimator();
+
// Set the exiting state first so if there is fixed rotation later, the running animation
// won't be interrupted by alpha animation for existing PiP.
mPipTransitionState.setTransitionState(PipTransitionState.EXITING_PIP);
@@ -806,18 +810,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
return;
}
- final PipAnimationController.PipTransitionAnimator<?> animator =
- mPipAnimationController.getCurrentAnimator();
- if (animator != null) {
- if (animator.getContentOverlayLeash() != null) {
- removeContentOverlay(animator.getContentOverlayLeash(),
- animator::clearContentOverlay);
- }
- animator.removeAllUpdateListeners();
- animator.removeAllListeners();
- animator.cancel();
- }
-
+ cancelCurrentAnimator();
onExitPipFinished(info);
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
@@ -1054,9 +1047,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
int direction = TRANSITION_DIRECTION_NONE;
if (animator != null) {
direction = animator.getTransitionDirection();
- animator.removeAllUpdateListeners();
- animator.removeAllListeners();
- animator.cancel();
+ PipAnimationController.quietCancel(animator);
// Do notify the listeners that this was canceled
sendOnPipTransitionCancelled(direction);
sendOnPipTransitionFinished(direction);
@@ -1590,10 +1581,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
// set a start delay on this animation.
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: Task vanished, skip fadeOutAndRemoveOverlay", TAG);
- animation.removeAllListeners();
- animation.removeAllUpdateListeners();
- animation.cancel();
- } else {
+ PipAnimationController.quietCancel(animation);
+ } else if (surface.isValid()) {
final float alpha = (float) animation.getAnimatedValue();
final SurfaceControl.Transaction transaction =
mSurfaceControlTransactionFactory.getTransaction();
@@ -1616,6 +1605,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
// Avoid double removal, which is fatal.
return;
}
+ if (surface == null || !surface.isValid()) {
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: trying to remove invalid content overlay (%s)", TAG, surface);
+ return;
+ }
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
tx.remove(surface);
tx.apply();
@@ -1632,6 +1626,18 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
tx.apply();
}
+ private void cancelCurrentAnimator() {
+ final PipAnimationController.PipTransitionAnimator<?> animator =
+ mPipAnimationController.getCurrentAnimator();
+ if (animator != null) {
+ if (animator.getContentOverlayLeash() != null) {
+ removeContentOverlay(animator.getContentOverlayLeash(),
+ animator::clearContentOverlay);
+ }
+ PipAnimationController.quietCancel(animator);
+ }
+ }
+
@VisibleForTesting
public void setSurfaceControlTransactionFactory(
PipSurfaceTransactionHelper.SurfaceControlTransactionFactory factory) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 60b406c7c3d9..c3e6d82df781 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -110,7 +110,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb
private PipAppOpsListener mAppOpsListener;
private PipMediaController mMediaController;
private PipBoundsAlgorithm mPipBoundsAlgorithm;
+ private PipKeepClearAlgorithm mPipKeepClearAlgorithm;
private PipBoundsState mPipBoundsState;
+ private PipMotionHelper mPipMotionHelper;
private PipTouchHandler mTouchHandler;
private PipTransitionController mPipTransitionController;
private TaskStackListenerImpl mTaskStackListener;
@@ -286,7 +288,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb
@Nullable
public static Pip create(Context context, DisplayController displayController,
PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm,
- PipBoundsState pipBoundsState, PipMediaController pipMediaController,
+ PipKeepClearAlgorithm pipKeepClearAlgorithm, PipBoundsState pipBoundsState,
+ PipMotionHelper pipMotionHelper, PipMediaController pipMediaController,
PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer,
PipTouchHandler pipTouchHandler, PipTransitionController pipTransitionController,
WindowManagerShellWrapper windowManagerShellWrapper,
@@ -301,7 +304,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
}
return new PipController(context, displayController, pipAppOpsListener, pipBoundsAlgorithm,
- pipBoundsState, pipMediaController,
+ pipKeepClearAlgorithm, pipBoundsState, pipMotionHelper, pipMediaController,
phonePipMenuController, pipTaskOrganizer, pipTouchHandler, pipTransitionController,
windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
oneHandedController, mainExecutor)
@@ -312,7 +315,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb
DisplayController displayController,
PipAppOpsListener pipAppOpsListener,
PipBoundsAlgorithm pipBoundsAlgorithm,
+ PipKeepClearAlgorithm pipKeepClearAlgorithm,
@NonNull PipBoundsState pipBoundsState,
+ PipMotionHelper pipMotionHelper,
PipMediaController pipMediaController,
PhonePipMenuController phonePipMenuController,
PipTaskOrganizer pipTaskOrganizer,
@@ -335,7 +340,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb
mWindowManagerShellWrapper = windowManagerShellWrapper;
mDisplayController = displayController;
mPipBoundsAlgorithm = pipBoundsAlgorithm;
+ mPipKeepClearAlgorithm = pipKeepClearAlgorithm;
mPipBoundsState = pipBoundsState;
+ mPipMotionHelper = pipMotionHelper;
mPipTaskOrganizer = pipTaskOrganizer;
mMainExecutor = mainExecutor;
mMediaController = pipMediaController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithm.java
new file mode 100644
index 000000000000..78084fafe197
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithm.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.pip.phone;
+
+import android.graphics.Rect;
+import android.util.ArraySet;
+
+import com.android.wm.shell.pip.PipBoundsAlgorithm;
+import com.android.wm.shell.pip.PipBoundsState;
+
+import java.util.Set;
+
+/**
+ * Calculates the adjusted position that does not occlude keep clear areas.
+ */
+public class PipKeepClearAlgorithm {
+
+ /**
+ * Adjusts the current position of PiP to avoid occluding keep clear areas. If the user has
+ * moved PiP manually, the unmodified current position will be returned instead.
+ */
+ public Rect adjust(PipBoundsState boundsState, PipBoundsAlgorithm boundsAlgorithm) {
+ if (boundsState.hasUserResizedPip()) {
+ return boundsState.getBounds();
+ }
+ return adjust(boundsAlgorithm.getEntryDestinationBounds(),
+ boundsState.getRestrictedKeepClearAreas(),
+ boundsState.getUnrestrictedKeepClearAreas(), boundsState.getDisplayBounds());
+ }
+
+ /** Returns a new {@code Rect} that does not occlude the provided keep clear areas. */
+ public Rect adjust(Rect defaultBounds, Set<Rect> restrictedKeepClearAreas,
+ Set<Rect> unrestrictedKeepClearAreas, Rect displayBounds) {
+ if (restrictedKeepClearAreas.isEmpty()) {
+ return defaultBounds;
+ }
+ Set<Rect> keepClearAreas = new ArraySet<>();
+ if (!restrictedKeepClearAreas.isEmpty()) {
+ keepClearAreas.addAll(restrictedKeepClearAreas);
+ }
+ Rect outBounds = new Rect(defaultBounds);
+ for (Rect r : keepClearAreas) {
+ if (Rect.intersects(r, outBounds)) {
+ if (tryOffsetUp(outBounds, r, displayBounds)) continue;
+ if (tryOffsetLeft(outBounds, r, displayBounds)) continue;
+ if (tryOffsetDown(outBounds, r, displayBounds)) continue;
+ if (tryOffsetRight(outBounds, r, displayBounds)) continue;
+ }
+ }
+ return outBounds;
+ }
+
+ private boolean tryOffsetLeft(Rect rectToMove, Rect rectToAvoid, Rect displayBounds) {
+ return tryOffset(rectToMove, rectToAvoid, displayBounds,
+ rectToAvoid.left - rectToMove.right, 0);
+ }
+
+ private boolean tryOffsetRight(Rect rectToMove, Rect rectToAvoid, Rect displayBounds) {
+ return tryOffset(rectToMove, rectToAvoid, displayBounds,
+ rectToAvoid.right - rectToMove.left, 0);
+ }
+
+ private boolean tryOffsetUp(Rect rectToMove, Rect rectToAvoid, Rect displayBounds) {
+ return tryOffset(rectToMove, rectToAvoid, displayBounds,
+ 0, rectToAvoid.top - rectToMove.bottom);
+ }
+
+ private boolean tryOffsetDown(Rect rectToMove, Rect rectToAvoid, Rect displayBounds) {
+ return tryOffset(rectToMove, rectToAvoid, displayBounds,
+ 0, rectToAvoid.bottom - rectToMove.top);
+ }
+
+ private boolean tryOffset(Rect rectToMove, Rect rectToAvoid, Rect displayBounds,
+ int dx, int dy) {
+ Rect tmp = new Rect(rectToMove);
+ tmp.offset(dx, dy);
+ if (!Rect.intersects(rectToAvoid, tmp) && displayBounds.contains(tmp)) {
+ rectToMove.offsetTo(tmp.left, tmp.top);
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index f8221d5aae24..f7057d454df9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -68,6 +68,7 @@ class SplitScreenTransitions {
private IBinder mAnimatingTransition = null;
OneShotRemoteHandler mPendingRemoteHandler = null;
private OneShotRemoteHandler mActiveRemoteHandler = null;
+ private boolean mEnterTransitionMerged;
private final Transitions.TransitionFinishCallback mRemoteFinishCB = this::onFinish;
@@ -229,6 +230,18 @@ class SplitScreenTransitions {
}
}
+ void onTransitionMerged(@NonNull IBinder transition) {
+ // Once a pending enter transition got merged, make sure to append the reset of finishing
+ // operations to the finish transition.
+ if (transition == mPendingEnter) {
+ mFinishTransaction = mTransactionPool.acquire();
+ mStageCoordinator.finishEnterSplitScreen(mFinishTransaction);
+ mPendingEnter = null;
+ mPendingRemoteHandler = null;
+ mEnterTransitionMerged = true;
+ }
+ }
+
void onFinish(WindowContainerTransaction wct, WindowContainerTransactionCallback wctCB) {
if (!mAnimations.isEmpty()) return;
if (mAnimatingTransition == mPendingEnter) {
@@ -238,18 +251,16 @@ class SplitScreenTransitions {
mPendingDismiss = null;
}
if (mAnimatingTransition == mPendingRecent) {
- // If the clean-up wct is null when finishing recent transition, it indicates it's
- // returning to home and thus no need to reorder tasks.
- final boolean returnToHome = wct == null;
- if (returnToHome) {
- wct = new WindowContainerTransaction();
+ if (!mEnterTransitionMerged) {
+ if (wct == null) wct = new WindowContainerTransaction();
+ mStageCoordinator.onRecentTransitionFinished(wct, mFinishTransaction);
}
- mStageCoordinator.onRecentTransitionFinished(returnToHome, wct, mFinishTransaction);
mPendingRecent = null;
}
mPendingRemoteHandler = null;
mActiveRemoteHandler = null;
mAnimatingTransition = null;
+ mEnterTransitionMerged = false;
mOnFinish.run();
if (mFinishTransaction != null) {
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 3cf8a45310ef..f625387a05d5 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,6 +30,7 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.transitTypeToString;
import static android.window.TransitionInfo.FLAG_FIRST_CUSTOM;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_ALIGN_CENTER;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
@@ -369,10 +370,15 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
sideOptions = sideOptions != null ? sideOptions : new Bundle();
setSideStagePosition(sidePosition, wct);
+ if (mMainStage.isActive()) {
+ mMainStage.evictAllChildren(wct);
+ mSideStage.evictAllChildren(wct);
+ } else {
+ // Build a request WCT that will launch both apps such that task 0 is on the main stage
+ // while task 1 is on the side stage.
+ mMainStage.activate(wct, false /* reparent */);
+ }
mSplitLayout.setDivideRatio(splitRatio);
- // Build a request WCT that will launch both apps such that task 0 is on the main stage
- // while task 1 is on the side stage.
- mMainStage.activate(wct, false /* reparent */);
updateWindowBounds(mSplitLayout, wct);
wct.reorder(mRootTaskInfo.token, true);
@@ -1507,16 +1513,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@Override
public void onTransitionMerged(@NonNull IBinder transition) {
- // Once the pending enter transition got merged, make sure to bring divider bar visible and
- // clear the pending transition from cache to prevent mess-up the following state.
- if (transition == mSplitTransitions.mPendingEnter) {
- final SurfaceControl.Transaction t = mTransactionPool.acquire();
- finishEnterSplitScreen(t);
- mSplitTransitions.mPendingEnter = null;
- mSplitTransitions.mPendingRemoteHandler = null;
- t.apply();
- mTransactionPool.release(t);
- }
+ mSplitTransitions.onTransitionMerged(transition);
}
@Override
@@ -1748,26 +1745,26 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return true;
}
- void onRecentTransitionFinished(boolean returnToHome, WindowContainerTransaction wct,
+ void onRecentTransitionFinished(WindowContainerTransaction wct,
SurfaceControl.Transaction finishT) {
- // Exclude the case that the split screen has been dismissed already.
- if (!mMainStage.isActive()) {
- // The latest split dismissing transition might be a no-op transition and thus won't
- // callback startAnimation, update split visibility here to cover this kind of no-op
- // transition case.
- setSplitsVisible(false);
- return;
+ // Check if the recent transition is finished by returning to the current split so we can
+ // restore the divider bar.
+ for (int i = 0; i < wct.getHierarchyOps().size(); ++i) {
+ final WindowContainerTransaction.HierarchyOp op = wct.getHierarchyOps().get(i);
+ final IBinder container = op.getContainer();
+ if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop()
+ && (mMainStage.containsContainer(container)
+ || mSideStage.containsContainer(container))) {
+ setDividerVisibility(true, finishT);
+ return;
+ }
}
- if (returnToHome) {
- // When returning to home from recent apps, the splitting tasks are already hidden, so
- // append the reset of dismissing operations into the clean-up wct.
- prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
- setSplitsVisible(false);
- logExit(EXIT_REASON_RETURN_HOME);
- } else {
- setDividerVisibility(true, finishT);
- }
+ // Dismiss the split screen is it's not returning to split.
+ prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
+ setSplitsVisible(false);
+ setDividerVisibility(false, finishT);
+ logExit(EXIT_REASON_UNKNOWN);
}
private void addDividerBarToTransition(@NonNull TransitionInfo info,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index eb513384d822..f9dd7c96294f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -31,6 +31,7 @@ import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.IBinder;
import android.util.SparseArray;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
@@ -47,6 +48,7 @@ import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.splitscreen.SplitScreen.StageType;
import java.io.PrintWriter;
+import java.util.function.Predicate;
/**
* Base class that handle common task org. related for split-screen stages.
@@ -119,63 +121,53 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
}
boolean containsToken(WindowContainerToken token) {
- if (token.equals(mRootTaskInfo.token)) {
- return true;
- }
-
- for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
- if (token.equals(mChildrenTaskInfo.valueAt(i).token)) {
- return true;
- }
- }
+ return contains(t -> t.token.equals(token));
+ }
- return false;
+ boolean containsContainer(IBinder binder) {
+ return contains(t -> t.token.asBinder() == binder);
}
/**
* Returns the top visible child task's id.
*/
int getTopVisibleChildTaskId() {
- for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
- final ActivityManager.RunningTaskInfo info = mChildrenTaskInfo.valueAt(i);
- if (info.isVisible) {
- return info.taskId;
- }
- }
- return INVALID_TASK_ID;
+ final ActivityManager.RunningTaskInfo taskInfo = getChildTaskInfo(t -> t.isVisible);
+ return taskInfo != null ? taskInfo.taskId : INVALID_TASK_ID;
}
/**
* Returns the top activity uid for the top child task.
*/
int getTopChildTaskUid() {
- for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
- final ActivityManager.RunningTaskInfo info = mChildrenTaskInfo.valueAt(i);
- if (info.topActivityInfo == null) {
- continue;
- }
- return info.topActivityInfo.applicationInfo.uid;
- }
- return 0;
+ final ActivityManager.RunningTaskInfo taskInfo =
+ getChildTaskInfo(t -> t.topActivityInfo != null);
+ return taskInfo != null ? taskInfo.topActivityInfo.applicationInfo.uid : 0;
}
/** @return {@code true} if this listener contains the currently focused task. */
boolean isFocused() {
- if (mRootTaskInfo == null) {
- return false;
- }
+ return contains(t -> t.isFocused);
+ }
- if (mRootTaskInfo.isFocused) {
+ private boolean contains(Predicate<ActivityManager.RunningTaskInfo> predicate) {
+ if (mRootTaskInfo != null && predicate.test(mRootTaskInfo)) {
return true;
}
+ return getChildTaskInfo(predicate) != null;
+ }
+
+ @Nullable
+ private ActivityManager.RunningTaskInfo getChildTaskInfo(
+ Predicate<ActivityManager.RunningTaskInfo> predicate) {
for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
- if (mChildrenTaskInfo.valueAt(i).isFocused) {
- return true;
+ final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i);
+ if (predicate.test(taskInfo)) {
+ return taskInfo;
}
}
-
- return false;
+ return null;
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 54d62edf2570..a0e176c7ea68 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -261,7 +261,8 @@ public class StartingSurfaceDrawer {
WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
params.setFitInsetsSides(0);
params.setFitInsetsTypes(0);
- params.format = PixelFormat.TRANSLUCENT;
+ params.format = suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN
+ ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT;
int windowFlags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 79e9cda3c389..c3eaa8ee1da0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -472,8 +472,9 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
}
final Rect clipRect = Transitions.isClosingType(change.getMode())
- ? mRotator.getEndBoundsInStartRotation(change)
- : change.getEndAbsBounds();
+ ? new Rect(mRotator.getEndBoundsInStartRotation(change))
+ : new Rect(change.getEndAbsBounds());
+ clipRect.offsetTo(0, 0);
if (delayedEdgeExtension) {
// If the edge extension needs to happen after the startTransition has been
@@ -973,7 +974,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
private static void applyTransformation(long time, SurfaceControl.Transaction t,
SurfaceControl leash, Animation anim, Transformation transformation, float[] matrix,
- Point position, float cornerRadius, @Nullable Rect clipRect) {
+ Point position, float cornerRadius, @Nullable Rect immutableClipRect) {
anim.getTransformation(time, transformation);
if (position != null) {
transformation.getMatrix().postTranslate(position.x, position.y);
@@ -981,6 +982,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
t.setMatrix(leash, transformation.getMatrix(), matrix);
t.setAlpha(leash, transformation.getAlpha());
+ final Rect clipRect = immutableClipRect == null ? null : new Rect(immutableClipRect);
Insets extensionInsets = Insets.min(transformation.getInsets(), Insets.NONE);
if (!extensionInsets.equals(Insets.NONE) && clipRect != null && !clipRect.isEmpty()) {
// Clip out any overflowing edge extension
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
index e9d438a569d5..5a364ddf3a8f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
@@ -39,7 +39,7 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
) {
private val mediaSessionManager: MediaSessionManager
get() = context.getSystemService(MediaSessionManager::class.java)
- ?: error("Could not get MediaSessionManager")
+ ?: error("Could not get MediaSessionManager")
private val mediaController: MediaController?
get() = mediaSessionManager.getActiveSessions(null).firstOrNull {
@@ -69,8 +69,10 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
action: String? = null,
stringExtras: Map<String, String>
) {
- launchViaIntentAndWaitShown(wmHelper, expectedWindowName, action, stringExtras,
- waitConditions = arrayOf(WindowManagerStateHelper.pipShownCondition))
+ launchViaIntentAndWaitShown(
+ wmHelper, expectedWindowName, action, stringExtras,
+ waitConditions = arrayOf(WindowManagerStateHelper.pipShownCondition)
+ )
}
/**
@@ -85,7 +87,7 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
// from "the bottom".
repeat(FOCUS_ATTEMPTS) {
uiDevice.findObject(selector)?.apply { if (isFocusedOrHasFocusedChild) return true }
- ?: error("The object we try to focus on is gone.")
+ ?: error("The object we try to focus on is gone.")
uiDevice.pressDPadDown()
uiDevice.waitForIdle()
@@ -100,29 +102,62 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
// Wait on WMHelper or simply wait for 3 seconds
wmHelper?.waitPipShown() ?: SystemClock.sleep(3_000)
// when entering pip, the dismiss button is visible at the start. to ensure the pip
- // animation is complete, wait until the pip dismiss button is no longer visible.
+ // animation is complete, wait until the pip dismiss button is no longer visible.
// b/176822698: dismiss-only state will be removed in the future
uiDevice.wait(Until.gone(By.res(SYSTEMUI_PACKAGE, "dismiss")), FIND_TIMEOUT)
}
+ @JvmOverloads
+ fun enterPipViaHomeButton(wmHelper: WindowManagerStateHelper) {
+ uiDevice.pressHome()
+
+ // Wait on WMHelper or simply wait for 3 seconds
+ wmHelper.waitPipShown() ?: SystemClock.sleep(3_000)
+ // when entering pip, the dismiss button is visible at the start. to ensure the pip
+ // animation is complete, wait until the pip dismiss button is no longer visible.
+ // b/176822698: dismiss-only state will be removed in the future
+ uiDevice.wait(Until.gone(By.res(SYSTEMUI_PACKAGE, "dismiss")), FIND_TIMEOUT)
+ }
+
+ @JvmOverloads
+ fun enterPipViaSwipeToHome(wmHelper: WindowManagerStateHelper) {
+ uiDevice.swipe(
+ uiDevice.displayWidth / 2, uiDevice.displayHeight - 10,
+ uiDevice.displayWidth / 2, uiDevice.displayHeight - 300, 3
+ )
+
+ // Wait on WMHelper or simply wait for 3 seconds
+ wmHelper.waitPipShown() ?: SystemClock.sleep(3_000)
+ // when entering pip, the dismiss button is visible at the start. to ensure the pip
+ // animation is complete, wait until the pip dismiss button is no longer visible.
+ // b/176822698: dismiss-only state will be removed in the future
+ uiDevice.wait(Until.gone(By.res(SYSTEMUI_PACKAGE, "dismiss")), FIND_TIMEOUT)
+ }
+
+ fun enableEnterPipOnUserLeaveHint() {
+ clickObject(ENTER_PIP_ON_USER_LEAVE_HINT)
+ }
+
fun clickStartMediaSessionButton() {
clickObject(MEDIA_SESSION_START_RADIO_BUTTON_ID)
}
fun checkWithCustomActionsCheckbox() = uiDevice
- .findObject(By.res(component.packageName, WITH_CUSTOM_ACTIONS_BUTTON_ID))
- ?.takeIf { it.isCheckable }
- ?.apply { if (!isChecked) clickObject(WITH_CUSTOM_ACTIONS_BUTTON_ID) }
- ?: error("'With custom actions' checkbox not found")
+ .findObject(By.res(component.packageName, WITH_CUSTOM_ACTIONS_BUTTON_ID))
+ ?.takeIf { it.isCheckable }
+ ?.apply { if (!isChecked) clickObject(WITH_CUSTOM_ACTIONS_BUTTON_ID) }
+ ?: error("'With custom actions' checkbox not found")
fun pauseMedia() = mediaController?.transportControls?.pause()
- ?: error("No active media session found")
+ ?: error("No active media session found")
fun stopMedia() = mediaController?.transportControls?.stop()
- ?: error("No active media session found")
+ ?: error("No active media session found")
- @Deprecated("Use PipAppHelper.closePipWindow(wmHelper) instead",
- ReplaceWith("closePipWindow(wmHelper)"))
+ @Deprecated(
+ "Use PipAppHelper.closePipWindow(wmHelper) instead",
+ ReplaceWith("closePipWindow(wmHelper)")
+ )
fun closePipWindow() {
if (isTelevision) {
uiDevice.closeTvPipWindow()
@@ -152,7 +187,7 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
val dismissSelector = By.res(SYSTEMUI_PACKAGE, "dismiss")
uiDevice.wait(Until.hasObject(dismissSelector), FIND_TIMEOUT)
val dismissPipObject = uiDevice.findObject(dismissSelector)
- ?: error("PIP window dismiss button not found")
+ ?: error("PIP window dismiss button not found")
val dismissButtonBounds = dismissPipObject.visibleBounds
uiDevice.click(dismissButtonBounds.centerX(), dismissButtonBounds.centerY())
}
@@ -172,7 +207,7 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
val expandSelector = By.res(SYSTEMUI_PACKAGE, "expand_button")
uiDevice.wait(Until.hasObject(expandSelector), FIND_TIMEOUT)
val expandPipObject = uiDevice.findObject(expandSelector)
- ?: error("PIP window expand button not found")
+ ?: error("PIP window expand button not found")
val expandButtonBounds = expandPipObject.visibleBounds
uiDevice.click(expandButtonBounds.centerX(), expandButtonBounds.centerY())
wmHelper.waitPipGone()
@@ -194,5 +229,6 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
private const val ENTER_PIP_BUTTON_ID = "enter_pip"
private const val WITH_CUSTOM_ACTIONS_BUTTON_ID = "with_custom_actions"
private const val MEDIA_SESSION_START_RADIO_BUTTON_ID = "media_session_start"
+ private const val ENTER_PIP_ON_USER_LEAVE_HINT = "enter_pip_on_leave_manual"
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
new file mode 100644
index 000000000000..04bf856fd9f8
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group3
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.Assume
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test entering pip from an app via [onUserLeaveHint] and by navigating to home.
+ *
+ * To run this test: `atest WMShellFlickerTests:EnterPipOnUserLeaveHintTest`
+ *
+ * Actions:
+ * Launch an app in full screen
+ * Select "Via code behind" radio button
+ * Press Home button to put [pipApp] in pip mode
+ *
+ * Notes:
+ * 1. All assertions are inherited from [EnterPipTest]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+class EnterPipOnUserLeaveHintTest(testSpec: FlickerTestParameter) : EnterPipTest(testSpec) {
+
+ /**
+ * Defines the transition used to run the test
+ */
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ setupAndTeardown(this)
+ setup {
+ eachRun {
+ pipApp.launchViaIntent(wmHelper)
+ pipApp.enableEnterPipOnUserLeaveHint()
+ }
+ }
+ teardown {
+ eachRun {
+ pipApp.exit(wmHelper)
+ }
+ }
+ transitions {
+ when (testSpec.isGesturalNavigation) {
+ true -> pipApp.enterPipViaSwipeToHome(wmHelper)
+ false -> pipApp.enterPipViaHomeButton(wmHelper)
+ }
+ }
+ }
+
+ override fun pipAppLayerAlwaysVisible() {
+ if (!testSpec.isGesturalNavigation) super.pipAppLayerAlwaysVisible() else {
+ // pip layer in gesture nav will disappear during transition
+ testSpec.assertLayers {
+ this.isVisible(pipApp.component)
+ .then().isInvisible(pipApp.component)
+ .then().isVisible(pipApp.component)
+ }
+ }
+ }
+
+ override fun pipLayerReduces() {
+ // in gestural nav the pip enters through alpha animation
+ Assume.assumeFalse(testSpec.isGesturalNavigation)
+ super.pipLayerReduces()
+ }
+
+ override fun focusChanges() {
+ // in gestural nav the focus goes to different activity on swipe up
+ Assume.assumeFalse(testSpec.isGesturalNavigation)
+ super.focusChanges()
+ }
+
+ override fun pipLayerRemainInsideVisibleBounds() {
+ if (!testSpec.isGesturalNavigation) super.pipLayerRemainInsideVisibleBounds() else {
+ // pip layer in gesture nav will disappear during transition
+ testSpec.assertLayersStart {
+ this.visibleRegion(pipApp.component).coversAtMost(displayBounds)
+ }
+ testSpec.assertLayersEnd {
+ this.visibleRegion(pipApp.component).coversAtMost(displayBounds)
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index 0640ac526bd0..b4267ffced5c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -43,7 +43,7 @@ import org.junit.runners.Parameterized
*
* Notes:
* 1. Some default assertions (e.g., nav bar, status bar and screen covered)
- * are inherited [PipTransition]
+ * are inherited from [PipTransition]
* 2. Part of the test setup occurs automatically via
* [com.android.server.wm.flicker.TransitionRunnerWithRules],
* including configuring navigation mode, initial orientation and ensuring no
@@ -54,7 +54,7 @@ import org.junit.runners.Parameterized
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group3
-class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+open class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
/**
* Defines the transition used to run the test
@@ -98,7 +98,7 @@ class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
*/
@Presubmit
@Test
- fun pipAppLayerAlwaysVisible() {
+ open fun pipAppLayerAlwaysVisible() {
testSpec.assertLayers {
this.isVisible(pipApp.component)
}
@@ -122,7 +122,7 @@ class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
*/
@Presubmit
@Test
- fun pipLayerRemainInsideVisibleBounds() {
+ open fun pipLayerRemainInsideVisibleBounds() {
testSpec.assertLayersVisibleRegion(pipApp.component) {
coversAtMost(displayBounds)
}
@@ -133,7 +133,7 @@ class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
*/
@Presubmit
@Test
- fun pipLayerReduces() {
+ open fun pipLayerReduces() {
val layerName = pipApp.component.toLayerName()
testSpec.assertLayers {
val pipLayerList = this.layers { it.name.contains(layerName) && it.isVisible }
@@ -175,7 +175,7 @@ class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
*/
@Presubmit
@Test
- fun focusChanges() {
+ open fun focusChanges() {
testSpec.assertEventLog {
this.focusChanges(pipApp.`package`, "NexusLauncherActivity")
}
@@ -192,8 +192,10 @@ class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
@JvmStatic
fun getParams(): List<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
- repetitions = 3)
+ .getConfigNonRotationTests(
+ supportedRotations = listOf(Surface.ROTATION_0),
+ repetitions = 3
+ )
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
index c620c31052b5..702710caded7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
@@ -24,15 +24,14 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.traces.common.Rect
-import com.android.wm.shell.flicker.layerBecomesVisible
-import com.android.wm.shell.flicker.layerIsVisibleAtEnd
import com.android.wm.shell.flicker.appWindowBecomesVisible
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
+import com.android.wm.shell.flicker.layerBecomesVisible
+import com.android.wm.shell.flicker.layerIsVisibleAtEnd
import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisible
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
import org.junit.Assume
import org.junit.Before
import org.junit.FixMethodOrder
@@ -72,15 +71,10 @@ class EnterSplitScreenByDragFromAllApps(
}
transitions {
taplInstrumentation.launchedAppState.taskbar
- .openAllApps()
- .getAppIcon(secondaryApp.appName)
- .dragToSplitscreen(secondaryApp.component.packageName,
- primaryApp.component.packageName)
-
- endDisplayBounds = wmHelper.currentState.layerState
- .displays.firstOrNull { !it.isVirtual }
- ?.layerStackSpace
- ?: error("Display not found")
+ .openAllApps()
+ .getAppIcon(secondaryApp.appName)
+ .dragToSplitscreen(secondaryApp.component.packageName,
+ primaryApp.component.packageName)
}
}
@@ -99,12 +93,12 @@ class EnterSplitScreenByDragFromAllApps(
@Presubmit
@Test
fun primaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
- testSpec.endRotation, primaryApp.component, isAppLeftTop(true))
+ testSpec.endRotation, primaryApp.component, false /* splitLeftTop */)
@Presubmit
@Test
fun secondaryAppBoundsBecomesVisible() = testSpec.splitAppLayerBoundsBecomesVisible(
- testSpec.endRotation, secondaryApp.component, isAppLeftTop(false))
+ testSpec.endRotation, secondaryApp.component, true /* splitLeftTop */)
@Presubmit
@Test
@@ -113,27 +107,17 @@ class EnterSplitScreenByDragFromAllApps(
@Presubmit
@Test
fun secondaryAppWindowBecomesVisible() =
- testSpec.appWindowBecomesVisible(secondaryApp.component)
-
- private fun isAppLeftTop(primary: Boolean): Boolean {
- return if (endDisplayBounds.width > endDisplayBounds.height) {
- !primary
- } else {
- primary
- }
- }
+ testSpec.appWindowBecomesVisible(secondaryApp.component)
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): List<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
- supportedNavigationModes =
- listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY))
+ repetitions = SplitScreenHelper.TEST_REPETITIONS,
+ // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+ supportedNavigationModes =
+ listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY))
}
-
- private lateinit var endDisplayBounds: Rect
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
index 909b77c87894..e9e7bb61660d 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
@@ -44,6 +44,32 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
+ android:checkedButton="@id/enter_pip_on_leave_disabled">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Enter PiP on home press"/>
+
+ <RadioButton
+ android:id="@+id/enter_pip_on_leave_disabled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Disabled"
+ android:onClick="onAutoPipSelected"/>
+
+ <RadioButton
+ android:id="@+id/enter_pip_on_leave_manual"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Via code behind"
+ android:onClick="onAutoPipSelected"/>
+ </RadioGroup>
+
+ <RadioGroup
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
android:checkedButton="@id/ratio_default">
<TextView
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
index a6ba7823e22d..a39aa4dc7bde 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
@@ -48,6 +48,7 @@ import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.CheckBox;
+import android.widget.RadioButton;
import java.util.ArrayList;
import java.util.Arrays;
@@ -201,6 +202,17 @@ public class PipActivity extends Activity {
super.onDestroy();
}
+ @Override
+ protected void onUserLeaveHint() {
+ // Only used when auto PiP is disabled. This is to simulate the behavior that an app
+ // supports regular PiP but not auto PiP.
+ final boolean manuallyEnterPip =
+ ((RadioButton) findViewById(R.id.enter_pip_on_leave_manual)).isChecked();
+ if (manuallyEnterPip) {
+ enterPictureInPictureMode();
+ }
+ }
+
private RemoteAction buildRemoteAction(Icon icon, String label, String action) {
final Intent intent = new Intent(action);
final PendingIntent pendingIntent =
@@ -216,6 +228,17 @@ public class PipActivity extends Activity {
enterPictureInPictureMode(mPipParamsBuilder.build());
}
+ public void onAutoPipSelected(View v) {
+ switch (v.getId()) {
+ case R.id.enter_pip_on_leave_manual:
+ // disable auto enter PiP
+ case R.id.enter_pip_on_leave_disabled:
+ mPipParamsBuilder.setAutoEnterEnabled(false);
+ setPictureInPictureParams(mPipParamsBuilder.build());
+ break;
+ }
+ }
+
public void onRatioSelected(View v) {
switch (v.getId()) {
case R.id.ratio_default:
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index df18133adcfb..abd55dd7d606 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -76,6 +76,7 @@ public class PipControllerTest extends ShellTestCase {
@Mock private PhonePipMenuController mMockPhonePipMenuController;
@Mock private PipAppOpsListener mMockPipAppOpsListener;
@Mock private PipBoundsAlgorithm mMockPipBoundsAlgorithm;
+ @Mock private PipKeepClearAlgorithm mMockPipKeepClearAlgorithm;
@Mock private PipSnapAlgorithm mMockPipSnapAlgorithm;
@Mock private PipMediaController mMockPipMediaController;
@Mock private PipTaskOrganizer mMockPipTaskOrganizer;
@@ -101,7 +102,8 @@ public class PipControllerTest extends ShellTestCase {
}).when(mMockExecutor).execute(any());
mPipController = new PipController(mContext, mMockDisplayController,
mMockPipAppOpsListener, mMockPipBoundsAlgorithm,
- mMockPipBoundsState, mMockPipMediaController,
+ mMockPipKeepClearAlgorithm,
+ mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTouchHandler,
mMockPipTransitionController, mMockWindowManagerShellWrapper,
mMockTaskStackListener, mPipParamsChangedForwarder,
@@ -134,7 +136,8 @@ public class PipControllerTest extends ShellTestCase {
assertNull(PipController.create(spyContext, mMockDisplayController,
mMockPipAppOpsListener, mMockPipBoundsAlgorithm,
- mMockPipBoundsState, mMockPipMediaController,
+ mMockPipKeepClearAlgorithm,
+ mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTouchHandler,
mMockPipTransitionController, mMockWindowManagerShellWrapper,
mMockTaskStackListener, mPipParamsChangedForwarder,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithmTest.java
new file mode 100644
index 000000000000..e0f7e35f8d02
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithmTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.pip.phone;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import android.graphics.Rect;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Set;
+
+/**
+ * Unit tests against {@link PipKeepClearAlgorithm}.
+ */
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class PipKeepClearAlgorithmTest extends ShellTestCase {
+
+ private PipKeepClearAlgorithm mPipKeepClearAlgorithm;
+ private static final Rect DISPLAY_BOUNDS = new Rect(0, 0, 1000, 1000);
+
+ @Before
+ public void setUp() throws Exception {
+ mPipKeepClearAlgorithm = new PipKeepClearAlgorithm();
+ }
+
+ @Test
+ public void adjust_withCollidingRestrictedKeepClearAreas_movesBounds() {
+ final Rect inBounds = new Rect(0, 0, 100, 100);
+ final Rect keepClearRect = new Rect(50, 50, 150, 150);
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(keepClearRect),
+ Set.of(), DISPLAY_BOUNDS);
+
+ assertFalse(outBounds.contains(keepClearRect));
+ }
+
+ @Test
+ public void adjust_withNonCollidingRestrictedKeepClearAreas_boundsDoNotChange() {
+ final Rect inBounds = new Rect(0, 0, 100, 100);
+ final Rect keepClearRect = new Rect(100, 100, 150, 150);
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(keepClearRect),
+ Set.of(), DISPLAY_BOUNDS);
+
+ assertEquals(inBounds, outBounds);
+ }
+
+ @Test
+ public void adjust_withCollidingUnrestrictedKeepClearAreas_boundsDoNotChange() {
+ // TODO(b/183746978): update this test to accommodate for the updated algorithm
+ final Rect inBounds = new Rect(0, 0, 100, 100);
+ final Rect keepClearRect = new Rect(50, 50, 150, 150);
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(),
+ Set.of(keepClearRect), DISPLAY_BOUNDS);
+
+ assertEquals(inBounds, outBounds);
+ }
+
+ @Test
+ public void adjust_withNonCollidingUnrestrictedKeepClearAreas_boundsDoNotChange() {
+ final Rect inBounds = new Rect(0, 0, 100, 100);
+ final Rect keepClearRect = new Rect(100, 100, 150, 150);
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(),
+ Set.of(keepClearRect), DISPLAY_BOUNDS);
+
+ assertEquals(inBounds, outBounds);
+ }
+}
diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp
index fecf26906c04..8191f5e6a83a 100644
--- a/libs/hwui/FrameInfo.cpp
+++ b/libs/hwui/FrameInfo.cpp
@@ -20,19 +20,33 @@
namespace android {
namespace uirenderer {
-const std::array FrameInfoNames{
- "Flags", "FrameTimelineVsyncId", "IntendedVsync",
- "Vsync", "InputEventId", "HandleInputStart",
- "AnimationStart", "PerformTraversalsStart", "DrawStart",
- "FrameDeadline", "FrameInterval", "FrameStartTime",
- "SyncQueued", "SyncStart", "IssueDrawCommandsStart",
- "SwapBuffers", "FrameCompleted", "DequeueBufferDuration",
- "QueueBufferDuration", "GpuCompleted", "SwapBuffersCompleted",
- "DisplayPresentTime",
+const std::array FrameInfoNames{"Flags",
+ "FrameTimelineVsyncId",
+ "IntendedVsync",
+ "Vsync",
+ "InputEventId",
+ "HandleInputStart",
+ "AnimationStart",
+ "PerformTraversalsStart",
+ "DrawStart",
+ "FrameDeadline",
+ "FrameInterval",
+ "FrameStartTime",
+ "SyncQueued",
+ "SyncStart",
+ "IssueDrawCommandsStart",
+ "SwapBuffers",
+ "FrameCompleted",
+ "DequeueBufferDuration",
+ "QueueBufferDuration",
+ "GpuCompleted",
+ "SwapBuffersCompleted",
+ "DisplayPresentTime",
+ "CommandSubmissionCompleted"
};
-static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 22,
+static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 23,
"Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)");
void FrameInfo::importUiThreadInfo(int64_t* info) {
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index 540a88b16dc9..564ee4f53a54 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -58,6 +58,7 @@ enum class FrameInfoIndex {
GpuCompleted,
SwapBuffersCompleted,
DisplayPresentTime,
+ CommandSubmissionCompleted,
// Must be the last value!
// Also must be kept in sync with FrameMetrics.java#FRAME_STATS_COUNT
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 744739accb2c..2aca41e41905 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -16,8 +16,15 @@
#include "SkiaOpenGLPipeline.h"
+#include <GrBackendSurface.h>
+#include <SkBlendMode.h>
+#include <SkImageInfo.h>
+#include <cutils/properties.h>
#include <gui/TraceUtils.h>
+#include <strings.h>
+
#include "DeferredLayerUpdater.h"
+#include "FrameInfo.h"
#include "LayerDrawable.h"
#include "LightingInfo.h"
#include "SkiaPipeline.h"
@@ -27,17 +34,9 @@
#include "renderstate/RenderState.h"
#include "renderthread/EglManager.h"
#include "renderthread/Frame.h"
+#include "renderthread/IRenderPipeline.h"
#include "utils/GLUtils.h"
-#include <GLES3/gl3.h>
-
-#include <GrBackendSurface.h>
-#include <SkBlendMode.h>
-#include <SkImageInfo.h>
-
-#include <cutils/properties.h>
-#include <strings.h>
-
using namespace android::uirenderer::renderthread;
namespace android {
@@ -69,12 +68,11 @@ Frame SkiaOpenGLPipeline::getFrame() {
return mEglManager.beginFrame(mEglSurface);
}
-bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
- const LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
- bool opaque, const LightInfo& lightInfo,
- const std::vector<sp<RenderNode>>& renderNodes,
- FrameInfoVisualizer* profiler) {
+IRenderPipeline::DrawResult SkiaOpenGLPipeline::draw(
+ const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
+ const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
+ const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo,
+ const std::vector<sp<RenderNode>>& renderNodes, FrameInfoVisualizer* profiler) {
if (!isCapturingSkp()) {
mEglManager.damageFrame(frame, dirty);
}
@@ -129,7 +127,7 @@ bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, con
dumpResourceCacheUsage();
}
- return true;
+ return {true, IRenderPipeline::DrawResult::kUnknownTime};
}
bool SkiaOpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index fddd97f1c5b3..186998a01745 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -36,11 +36,14 @@ public:
renderthread::MakeCurrentResult makeCurrent() override;
renderthread::Frame getFrame() override;
- bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
- const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo,
- const std::vector<sp<RenderNode> >& renderNodes,
- FrameInfoVisualizer* profiler) override;
+ renderthread::IRenderPipeline::DrawResult draw(const renderthread::Frame& frame,
+ const SkRect& screenDirty, const SkRect& dirty,
+ const LightGeometry& lightGeometry,
+ LayerUpdateQueue* layerUpdateQueue,
+ const Rect& contentDrawBounds, bool opaque,
+ const LightInfo& lightInfo,
+ const std::vector<sp<RenderNode> >& renderNodes,
+ FrameInfoVisualizer* profiler) override;
GrSurfaceOrigin getSurfaceOrigin() override { return kBottomLeft_GrSurfaceOrigin; }
bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) override;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 99fd463b0660..905d46e58014 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -16,7 +16,15 @@
#include "SkiaVulkanPipeline.h"
+#include <GrDirectContext.h>
+#include <GrTypes.h>
+#include <SkSurface.h>
+#include <SkTypes.h>
+#include <cutils/properties.h>
#include <gui/TraceUtils.h>
+#include <strings.h>
+#include <vk/GrVkTypes.h>
+
#include "DeferredLayerUpdater.h"
#include "LightingInfo.h"
#include "Readback.h"
@@ -26,16 +34,7 @@
#include "VkInteropFunctorDrawable.h"
#include "renderstate/RenderState.h"
#include "renderthread/Frame.h"
-
-#include <SkSurface.h>
-#include <SkTypes.h>
-
-#include <GrDirectContext.h>
-#include <GrTypes.h>
-#include <vk/GrVkTypes.h>
-
-#include <cutils/properties.h>
-#include <strings.h>
+#include "renderthread/IRenderPipeline.h"
using namespace android::uirenderer::renderthread;
@@ -64,15 +63,14 @@ Frame SkiaVulkanPipeline::getFrame() {
return vulkanManager().dequeueNextBuffer(mVkSurface);
}
-bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
- const LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
- bool opaque, const LightInfo& lightInfo,
- const std::vector<sp<RenderNode>>& renderNodes,
- FrameInfoVisualizer* profiler) {
+IRenderPipeline::DrawResult SkiaVulkanPipeline::draw(
+ const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
+ const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
+ const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo,
+ const std::vector<sp<RenderNode>>& renderNodes, FrameInfoVisualizer* profiler) {
sk_sp<SkSurface> backBuffer = mVkSurface->getCurrentSkSurface();
if (backBuffer.get() == nullptr) {
- return false;
+ return {false, -1};
}
// update the coordinates of the global light position based on surface rotation
@@ -94,9 +92,10 @@ bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, con
profiler->draw(profileRenderer);
}
+ nsecs_t submissionTime = IRenderPipeline::DrawResult::kUnknownTime;
{
ATRACE_NAME("flush commands");
- vulkanManager().finishFrame(backBuffer.get());
+ submissionTime = vulkanManager().finishFrame(backBuffer.get());
}
layerUpdateQueue->clear();
@@ -105,7 +104,7 @@ bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, con
dumpResourceCacheUsage();
}
- return true;
+ return {true, submissionTime};
}
bool SkiaVulkanPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 56d42e013f31..ada6af67d4a0 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -33,11 +33,14 @@ public:
renderthread::MakeCurrentResult makeCurrent() override;
renderthread::Frame getFrame() override;
- bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
- const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo,
- const std::vector<sp<RenderNode> >& renderNodes,
- FrameInfoVisualizer* profiler) override;
+ renderthread::IRenderPipeline::DrawResult draw(const renderthread::Frame& frame,
+ const SkRect& screenDirty, const SkRect& dirty,
+ const LightGeometry& lightGeometry,
+ LayerUpdateQueue* layerUpdateQueue,
+ const Rect& contentDrawBounds, bool opaque,
+ const LightInfo& lightInfo,
+ const std::vector<sp<RenderNode> >& renderNodes,
+ FrameInfoVisualizer* profiler) override;
GrSurfaceOrigin getSurfaceOrigin() override { return kTopLeft_GrSurfaceOrigin; }
bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) override;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 122c77f3dadc..976117b9bbd4 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -512,9 +512,9 @@ nsecs_t CanvasContext::draw() {
ATRACE_FORMAT("Drawing " RECT_STRING, SK_RECT_ARGS(dirty));
- bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue,
- mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes,
- &(profiler()));
+ const auto drawResult = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry,
+ &mLayerUpdateQueue, mContentDrawBounds, mOpaque,
+ mLightInfo, mRenderNodes, &(profiler()));
uint64_t frameCompleteNr = getFrameNumber();
@@ -534,8 +534,11 @@ nsecs_t CanvasContext::draw() {
bool requireSwap = false;
int error = OK;
- bool didSwap =
- mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, &requireSwap);
+ bool didSwap = mRenderPipeline->swapBuffers(frame, drawResult.success, windowDirty,
+ mCurrentFrameInfo, &requireSwap);
+
+ mCurrentFrameInfo->set(FrameInfoIndex::CommandSubmissionCompleted) = std::max(
+ drawResult.commandSubmissionTime, mCurrentFrameInfo->get(FrameInfoIndex::SwapBuffers));
mIsDirty = false;
@@ -753,7 +756,8 @@ void CanvasContext::onSurfaceStatsAvailable(void* context, int32_t surfaceContro
if (frameInfo != nullptr) {
frameInfo->set(FrameInfoIndex::FrameCompleted) = std::max(gpuCompleteTime,
frameInfo->get(FrameInfoIndex::SwapBuffersCompleted));
- frameInfo->set(FrameInfoIndex::GpuCompleted) = gpuCompleteTime;
+ frameInfo->set(FrameInfoIndex::GpuCompleted) = std::max(
+ gpuCompleteTime, frameInfo->get(FrameInfoIndex::CommandSubmissionCompleted));
std::scoped_lock lock(instance->mFrameMetricsReporterMutex);
instance->mJankTracker.finishFrame(*frameInfo, instance->mFrameMetricsReporter, frameNumber,
surfaceControlId);
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index aceb5a528fc8..ef58bc553c23 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -49,11 +49,21 @@ class IRenderPipeline {
public:
virtual MakeCurrentResult makeCurrent() = 0;
virtual Frame getFrame() = 0;
- virtual bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
- const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo,
- const std::vector<sp<RenderNode>>& renderNodes,
- FrameInfoVisualizer* profiler) = 0;
+
+ // Result of IRenderPipeline::draw
+ struct DrawResult {
+ // True if draw() succeeded, false otherwise
+ bool success = false;
+ // If drawing was successful, reports the time at which command
+ // submission occurred. -1 if this time is unknown.
+ static constexpr nsecs_t kUnknownTime = -1;
+ nsecs_t commandSubmissionTime = kUnknownTime;
+ };
+ virtual DrawResult draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
+ const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
+ const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo,
+ const std::vector<sp<RenderNode>>& renderNodes,
+ FrameInfoVisualizer* profiler) = 0;
virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) = 0;
virtual DeferredLayerUpdater* createTextureLayer() = 0;
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index a9ff2c60fdbe..718d4a16d5c8 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -494,7 +494,7 @@ static void destroy_semaphore(void* context) {
}
}
-void VulkanManager::finishFrame(SkSurface* surface) {
+nsecs_t VulkanManager::finishFrame(SkSurface* surface) {
ATRACE_NAME("Vulkan finish frame");
ALOGE_IF(mSwapSemaphore != VK_NULL_HANDLE || mDestroySemaphoreContext != nullptr,
"finishFrame already has an outstanding semaphore");
@@ -530,6 +530,7 @@ void VulkanManager::finishFrame(SkSurface* surface) {
GrDirectContext* context = GrAsDirectContext(surface->recordingContext());
ALOGE_IF(!context, "Surface is not backed by gpu");
context->submit();
+ const nsecs_t submissionTime = systemTime();
if (semaphore != VK_NULL_HANDLE) {
if (submitted == GrSemaphoresSubmitted::kYes) {
mSwapSemaphore = semaphore;
@@ -558,6 +559,8 @@ void VulkanManager::finishFrame(SkSurface* surface) {
}
}
skiapipeline::ShaderCache::get().onVkFrameFlushed(context);
+
+ return submissionTime;
}
void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect) {
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index b816649edf6e..b8c2bdf112f8 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -84,7 +84,9 @@ public:
void destroySurface(VulkanSurface* surface);
Frame dequeueNextBuffer(VulkanSurface* surface);
- void finishFrame(SkSurface* surface);
+ // Finishes the frame and submits work to the GPU
+ // Returns the estimated start time for intiating GPU work, -1 otherwise.
+ nsecs_t finishFrame(SkSurface* surface);
void swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect);
// Inserts a wait on fence command into the Vulkan command buffer.
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 3630d0c14d9e..3a0699ecb0ee 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -1079,11 +1079,20 @@ public final class MediaFormat {
/**
* A key describing the desired profile to be used by an encoder.
+ * <p>
* The associated value is an integer.
* Constants are declared in {@link MediaCodecInfo.CodecProfileLevel}.
* This key is used as a hint, and is only supported for codecs
- * that specify a profile. Note: Codecs are free to use all the available
- * coding tools at the specified profile.
+ * that specify a profile. When configuring profile, encoder configuration
+ * may fail if other parameters are not compatible with the desired
+ * profile or if the desired profile is not supported, but it may also
+ * fail silently (where the encoder ends up using a different, compatible profile.)
+ * <p class="note">
+ * <strong>Note:</strong> Codecs are free to use all the available
+ * coding tools at the specified profile, but may ultimately choose to not do so.
+ * <p class="note">
+ * <strong>Note:</strong> When configuring video encoders, profile must be
+ * set together with {@link #KEY_LEVEL level}.
*
* @see MediaCodecInfo.CodecCapabilities#profileLevels
*/
@@ -1091,12 +1100,22 @@ public final class MediaFormat {
/**
* A key describing the desired profile to be used by an encoder.
+ * <p>
* The associated value is an integer.
* Constants are declared in {@link MediaCodecInfo.CodecProfileLevel}.
* This key is used as a further hint when specifying a desired profile,
* and is only supported for codecs that specify a level.
* <p>
* This key is ignored if the {@link #KEY_PROFILE profile} is not specified.
+ * Otherwise, the value should be a level compatible with the configured encoding
+ * parameters.
+ * <p class="note">
+ * <strong>Note:</strong> This key cannot be used to constrain the encoder's
+ * output to a maximum encoding level. Encoders are free to target a different
+ * level if the configured encoding parameters dictate it. Nevertheless,
+ * encoders shall use (and encode) a level sufficient to decode the generated
+ * bitstream, though they may exceed the (Video) Buffering Verifier limits for
+ * that encoded level.
*
* @see MediaCodecInfo.CodecCapabilities#profileLevels
*/
diff --git a/media/java/android/media/audio/common/AidlConversion.java b/media/java/android/media/audio/common/AidlConversion.java
index f17189dedcba..491a8ec2c130 100644
--- a/media/java/android/media/audio/common/AidlConversion.java
+++ b/media/java/android/media/audio/common/AidlConversion.java
@@ -695,6 +695,10 @@ public class AidlConversion {
aidl.type = AudioDeviceType.OUT_SPEAKER;
aidl.connection = AudioDeviceDescription.CONNECTION_BT_LE;
break;
+ case AudioSystem.DEVICE_OUT_BLE_BROADCAST:
+ aidl.type = AudioDeviceType.OUT_BROADCAST;
+ aidl.connection = AudioDeviceDescription.CONNECTION_BT_LE;
+ break;
case AudioSystem.DEVICE_IN_BUILTIN_MIC:
aidl.type = AudioDeviceType.IN_MICROPHONE;
break;
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index e5673a613b59..13f7ee6e8c8b 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -2163,7 +2163,9 @@ public class Tuner implements AutoCloseable {
if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_LNB, mLnbLock)
&& mLnb != null) {
mLnb.setCallbackAndOwner(this, executor, cb);
- setLnb(mLnb);
+ if (mFrontendHandle != null && mFrontend != null) {
+ setLnb(mLnb);
+ }
return mLnb;
}
return null;
@@ -2197,7 +2199,9 @@ public class Tuner implements AutoCloseable {
}
mLnb = newLnb;
mLnb.setCallbackAndOwner(this, executor, cb);
- setLnb(mLnb);
+ if (mFrontendHandle != null && mFrontend != null) {
+ setLnb(mLnb);
+ }
}
return mLnb;
} finally {
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 5850a81b8295..95599bd41e8d 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -730,6 +730,7 @@ status_t JMediaCodec::getOutputFrame(
switch (c2Buffer->data().type()) {
case C2BufferData::LINEAR: {
std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
+ context->mCodecNames.push_back(mNameAtCreation.c_str());
context->mBuffer = c2Buffer;
ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
@@ -769,6 +770,7 @@ status_t JMediaCodec::getOutputFrame(
} else {
if (!mGraphicOutput) {
std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
+ context->mCodecNames.push_back(mNameAtCreation.c_str());
context->mLegacyBuffer = buffer;
ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
@@ -812,7 +814,6 @@ status_t JMediaCodec::getOutputFrame(
return OK;
}
-
status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
AString name;
@@ -2286,6 +2287,108 @@ static status_t ConvertKeyValueListsToAMessage(
return OK;
}
+static bool obtain(
+ JMediaCodecLinearBlock *context,
+ int capacity,
+ const std::vector<std::string> &names,
+ bool secure) {
+ if (secure) {
+ // Start at 1MB, which is an arbitrary starting point that can
+ // increase when needed.
+ constexpr size_t kInitialDealerCapacity = 1048576;
+ thread_local sp<MemoryDealer> sDealer = new MemoryDealer(
+ kInitialDealerCapacity, "JNI(1MB)");
+ context->mMemory = sDealer->allocate(capacity);
+ if (context->mMemory == nullptr) {
+ size_t newDealerCapacity = sDealer->getMemoryHeap()->getSize() * 2;
+ while (capacity * 2 > newDealerCapacity) {
+ newDealerCapacity *= 2;
+ }
+ ALOGI("LinearBlock.native_obtain: "
+ "Dealer capacity increasing from %zuMB to %zuMB",
+ sDealer->getMemoryHeap()->getSize() / 1048576,
+ newDealerCapacity / 1048576);
+ sDealer = new MemoryDealer(
+ newDealerCapacity,
+ AStringPrintf("JNI(%zuMB)", newDealerCapacity).c_str());
+ context->mMemory = sDealer->allocate(capacity);
+ }
+ context->mHidlMemory = hardware::fromHeap(context->mMemory->getMemory(
+ &context->mHidlMemoryOffset, &context->mHidlMemorySize));
+ } else {
+ context->mBlock = MediaCodec::FetchLinearBlock(capacity, names);
+ if (!context->mBlock) {
+ return false;
+ }
+ }
+ context->mCodecNames = names;
+ return true;
+}
+
+static void extractMemoryFromContext(
+ JMediaCodecLinearBlock *context,
+ jint offset,
+ jint size,
+ sp<hardware::HidlMemory> *memory) {
+ *memory = context->toHidlMemory();
+ if (*memory == nullptr) {
+ if (!context->mBlock) {
+ ALOGW("extractMemoryFromContext: the buffer is missing both IMemory and C2Block");
+ return;
+ }
+ ALOGD("extractMemoryFromContext: realloc & copying from C2Block to IMemory (cap=%zu)",
+ context->capacity());
+ if (!obtain(context, context->capacity(),
+ context->mCodecNames, true /* secure */)) {
+ ALOGW("extractMemoryFromContext: failed to obtain secure block");
+ return;
+ }
+ C2WriteView view = context->mBlock->map().get();
+ if (view.error() != C2_OK) {
+ ALOGW("extractMemoryFromContext: failed to map C2Block (%d)", view.error());
+ return;
+ }
+ uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
+ memcpy(memoryPtr + offset, view.base() + offset, size);
+ context->mBlock.reset();
+ context->mReadWriteMapping.reset();
+ *memory = context->toHidlMemory();
+ }
+}
+
+static void extractBufferFromContext(
+ JMediaCodecLinearBlock *context,
+ jint offset,
+ jint size,
+ std::shared_ptr<C2Buffer> *buffer) {
+ *buffer = context->toC2Buffer(offset, size);
+ if (*buffer == nullptr) {
+ if (!context->mMemory) {
+ ALOGW("extractBufferFromContext: the buffer is missing both IMemory and C2Block");
+ return;
+ }
+ ALOGD("extractBufferFromContext: realloc & copying from IMemory to C2Block (cap=%zu)",
+ context->capacity());
+ if (obtain(context, context->capacity(),
+ context->mCodecNames, false /* secure */)) {
+ ALOGW("extractBufferFromContext: failed to obtain non-secure block");
+ return;
+ }
+ C2WriteView view = context->mBlock->map().get();
+ if (view.error() != C2_OK) {
+ ALOGW("extractBufferFromContext: failed to map C2Block (%d)", view.error());
+ return;
+ }
+ uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
+ memcpy(view.base() + offset, memoryPtr + offset, size);
+ context->mMemory.clear();
+ context->mHidlMemory.clear();
+ context->mHidlMemorySize = 0;
+ context->mHidlMemoryOffset = 0;
+ *buffer = context->toC2Buffer(offset, size);
+ }
+}
+
static void android_media_MediaCodec_native_queueLinearBlock(
JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
jint offset, jint size, jobject cryptoInfoObj,
@@ -2314,12 +2417,10 @@ static void android_media_MediaCodec_native_queueLinearBlock(
JMediaCodecLinearBlock *context =
(JMediaCodecLinearBlock *)env->GetLongField(bufferObj, gLinearBlockInfo.contextId);
if (codec->hasCryptoOrDescrambler()) {
- memory = context->toHidlMemory();
- // TODO: copy if memory is null
+ extractMemoryFromContext(context, offset, size, &memory);
offset += context->mHidlMemoryOffset;
} else {
- buffer = context->toC2Buffer(offset, size);
- // TODO: copy if buffer is null
+ extractBufferFromContext(context, offset, size, &buffer);
}
}
env->MonitorExit(lock.get());
@@ -2354,6 +2455,7 @@ static void android_media_MediaCodec_native_queueLinearBlock(
flags,
tunings,
&errorDetailMsg);
+ ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
} else {
if (!buffer) {
ALOGI("queueLinearBlock: no C2Buffer found");
@@ -3300,33 +3402,9 @@ static void android_media_MediaCodec_LinearBlock_native_obtain(
hasNonSecure = true;
}
}
- if (hasSecure && !hasNonSecure) {
- constexpr size_t kInitialDealerCapacity = 1048576; // 1MB
- thread_local sp<MemoryDealer> sDealer = new MemoryDealer(
- kInitialDealerCapacity, "JNI(1MB)");
- context->mMemory = sDealer->allocate(capacity);
- if (context->mMemory == nullptr) {
- size_t newDealerCapacity = sDealer->getMemoryHeap()->getSize() * 2;
- while (capacity * 2 > newDealerCapacity) {
- newDealerCapacity *= 2;
- }
- ALOGI("LinearBlock.native_obtain: "
- "Dealer capacity increasing from %zuMB to %zuMB",
- sDealer->getMemoryHeap()->getSize() / 1048576,
- newDealerCapacity / 1048576);
- sDealer = new MemoryDealer(
- newDealerCapacity,
- AStringPrintf("JNI(%zuMB)", newDealerCapacity).c_str());
- context->mMemory = sDealer->allocate(capacity);
- }
- context->mHidlMemory = hardware::fromHeap(context->mMemory->getMemory(
- &context->mHidlMemoryOffset, &context->mHidlMemorySize));
- } else {
- context->mBlock = MediaCodec::FetchLinearBlock(capacity, names);
- if (!context->mBlock) {
- jniThrowException(env, "java/io/IOException", nullptr);
- return;
- }
+ if (!obtain(context.get(), capacity, names, (hasSecure && !hasNonSecure) /* secure */)) {
+ jniThrowException(env, "java/io/IOException", nullptr);
+ return;
}
env->CallVoidMethod(
thiz,
diff --git a/media/jni/android_media_MediaCodecLinearBlock.h b/media/jni/android_media_MediaCodecLinearBlock.h
index ae2d3a264abc..c7530207d1fa 100644
--- a/media/jni/android_media_MediaCodecLinearBlock.h
+++ b/media/jni/android_media_MediaCodecLinearBlock.h
@@ -25,6 +25,8 @@
namespace android {
struct JMediaCodecLinearBlock {
+ std::vector<std::string> mCodecNames;
+
std::shared_ptr<C2Buffer> mBuffer;
std::shared_ptr<C2ReadView> mReadonlyMapping;
@@ -40,7 +42,7 @@ struct JMediaCodecLinearBlock {
std::once_flag mCopyWarningFlag;
- std::shared_ptr<C2Buffer> toC2Buffer(size_t offset, size_t size) {
+ std::shared_ptr<C2Buffer> toC2Buffer(size_t offset, size_t size) const {
if (mBuffer) {
if (mBuffer->data().type() != C2BufferData::LINEAR) {
return nullptr;
@@ -64,12 +66,22 @@ struct JMediaCodecLinearBlock {
return nullptr;
}
- sp<hardware::HidlMemory> toHidlMemory() {
+ sp<hardware::HidlMemory> toHidlMemory() const {
if (mHidlMemory) {
return mHidlMemory;
}
return nullptr;
}
+
+ size_t capacity() const {
+ if (mBlock) {
+ return mBlock->capacity();
+ }
+ if (mMemory) {
+ return mMemory->size();
+ }
+ return 0;
+ }
};
} // namespace android
diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml
index fc449d5d4a46..3d35e55ed68c 100644
--- a/packages/CompanionDeviceManager/res/values-pa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml
@@ -38,8 +38,8 @@
<string name="helper_summary_computer" msgid="1676407599909474428">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸਾਂ ਵਿਚਕਾਰ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ਡੀਵਾਈਸ"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
- <string name="consent_yes" msgid="8344487259618762872">"ਇਜਾਜ਼ਤ ਦਿਓ"</string>
- <string name="consent_no" msgid="2640796915611404382">"ਇਜਾਜ਼ਤ ਨਾ ਦਿਓ"</string>
+ <string name="consent_yes" msgid="8344487259618762872">"ਆਗਿਆ ਦਿਓ"</string>
+ <string name="consent_no" msgid="2640796915611404382">"ਆਗਿਆ ਨਾ ਦਿਓ"</string>
<string name="consent_back" msgid="2560683030046918882">"ਪਿੱਛੇ"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"ਐਪ ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਆਪਣੀ ਘੜੀ \'ਤੇ ਟ੍ਰਾਂਸਫ਼ਰ ਕਰੋ"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"ਤੁਹਾਡੀ ਘੜੀ ਦਾ ਸੈੱਟਅੱਪ ਕਰਨਾ ਆਸਾਨ ਬਣਾਉਣ ਲਈ, ਤੁਹਾਡੀ ਘੜੀ \'ਤੇ ਸਥਾਪਤ ਐਪਾਂ ਸੈੱਟਅੱਪ ਦੌਰਾਨ ਉਹੀ ਇਜਾਜ਼ਤਾਂ ਵਰਤਣਗੀਆਂ ਜੋ ਤੁਹਾਡਾ ਫ਼ੋਨ ਵਰਤਦਾ ਹੈ।\n\n ਇਨ੍ਹਾਂ ਇਜਾਜ਼ਤਾਂ ਵਿੱਚ ਤੁਹਾਡੀ ਘੜੀ ਦੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਅਤੇ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਸ਼ਾਮਲ ਹੋ ਸਕਦੀ ਹੈ।"</string>
diff --git a/packages/EasterEgg/res/drawable/android_13.xml b/packages/EasterEgg/res/drawable/android_13.xml
new file mode 100644
index 000000000000..edc44ce4eaa3
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android_13.xml
@@ -0,0 +1,42 @@
+<!--
+Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:pathData="M37,39.03l8.58,0l0,33.94"
+ android:strokeWidth="6.2"
+ android:strokeColor="@android:color/system_accent1_800"
+ />
+ <path
+ android:pathData="M53.98,39.03h11.31l-5.59,11.31c6.02,0.96 10.11,6.62 9.15,12.64c-0.85,5.3 -5.38,9.22 -10.74,9.29c-1.38,-0 -2.76,-0.26 -4.05,-0.75"
+ android:strokeWidth="6.2"
+ android:strokeColor="@android:color/system_accent1_800"
+ />
+ <path
+ android:pathData="M37,39.03l8.58,0l0,33.94"
+ android:strokeWidth="1.56"
+ android:strokeColor="@android:color/system_neutral1_100"
+ />
+ <path
+ android:pathData="M53.98,39.03h11.31l-5.59,11.31c6.02,0.96 10.11,6.62 9.15,12.64c-0.85,5.3 -5.38,9.22 -10.74,9.29c-1.38,-0 -2.76,-0.26 -4.05,-0.75"
+ android:strokeWidth="1.56"
+ android:strokeColor="@android:color/system_neutral1_100"
+ />
+
+</vector> \ No newline at end of file
diff --git a/packages/EasterEgg/res/drawable/android_13_mono.xml b/packages/EasterEgg/res/drawable/android_13_mono.xml
new file mode 100644
index 000000000000..55c1bcd94831
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android_13_mono.xml
@@ -0,0 +1,31 @@
+<!--
+Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:pathData="M37,39.03l8.58,0l0,33.94"
+ android:strokeWidth="6.2"
+ android:strokeColor="@android:color/system_accent1_800"
+ />
+ <path
+ android:pathData="M53.98,39.03h11.31l-5.59,11.31c6.02,0.96 10.11,6.62 9.15,12.64c-0.85,5.3 -5.38,9.22 -10.74,9.29c-1.38,-0 -2.76,-0.26 -4.05,-0.75"
+ android:strokeWidth="6.2"
+ android:strokeColor="@android:color/system_accent1_800"
+ />
+</vector> \ No newline at end of file
diff --git a/packages/EasterEgg/res/drawable/icon.xml b/packages/EasterEgg/res/drawable/icon.xml
index 7054962b3503..cdac1f98be30 100644
--- a/packages/EasterEgg/res/drawable/icon.xml
+++ b/packages/EasterEgg/res/drawable/icon.xml
@@ -15,5 +15,6 @@ Copyright (C) 2018 The Android Open Source Project
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/icon_bg"/>
- <foreground android:drawable="@drawable/android_s"/>
+ <foreground android:drawable="@drawable/android_13"/>
+ <monochrome android:drawable="@drawable/android_13_mono"/>
</adaptive-icon>
diff --git a/packages/EasterEgg/res/drawable/icon_bg.xml b/packages/EasterEgg/res/drawable/icon_bg.xml
index d08e160ea312..231b4b802ecc 100644
--- a/packages/EasterEgg/res/drawable/icon_bg.xml
+++ b/packages/EasterEgg/res/drawable/icon_bg.xml
@@ -14,5 +14,5 @@ Copyright (C) 2018 The Android Open Source Project
limitations under the License.
-->
<color xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@android:color/system_accent2_500" />
+ android:color="@android:color/system_accent3_400" />
diff --git a/packages/PackageInstaller/res/values-ar/strings.xml b/packages/PackageInstaller/res/values-ar/strings.xml
index d85d15985918..1dea809a0d38 100644
--- a/packages/PackageInstaller/res/values-ar/strings.xml
+++ b/packages/PackageInstaller/res/values-ar/strings.xml
@@ -83,7 +83,7 @@
<string name="app_name_unknown" msgid="6881210203354323926">"غير معروف"</string>
<string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"لأغراض الأمان، غير مسموح حاليًا لجهازك اللوحي بتثبيت تطبيقات غير معروفة من هذا المصدر. ويمكنك تغيير ذلك في \"الإعدادات\"."</string>
<string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"لأغراض الأمان، غير مسموح حاليًا لجهاز التلفزيون الذي تستخدمه بتثبيت تطبيقات غير معروفة من هذا المصدر. ويمكنك تغيير ذلك في \"الإعدادات\"."</string>
- <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"لأغراض الأمان، غير مسموح حاليًا لهاتفك بتثبيت تطبيقات غير معروفة من هذا المصدر. ويمكنك تغيير ذلك في \"الإعدادات\"."</string>
+ <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"لأغراض الأمان، غير مسموح حاليًا لهاتفك بتثبيت تطبيقات غير معروفة من هذا المصدر. يمكنك تغيير ذلك في \"الإعدادات\"."</string>
<string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"يعتبر الهاتف والبيانات الشخصية أكثر عرضة لهجوم التطبيقات غير المعروفة. من خلال تثبيت هذا التطبيق، توافق على تحمل مسؤولية أي ضرر يحدث لهاتفك أو فقدان البيانات الذي قد ينتج عن استخدامه."</string>
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"يعتبر الجهاز اللوحي والبيانات الشخصية أكثر عرضة لهجوم التطبيقات غير المعروفة. من خلال تثبيت هذا التطبيق، توافق على تحمل مسؤولية أي ضرر يحدث للجهاز اللوحي أو فقدان البيانات الذي قد ينتج عن استخدامه."</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"يعتبر جهاز التلفزيون والبيانات الشخصية أكثر عرضة لهجوم التطبيقات غير المعروفة. من خلال تثبيت هذا التطبيق، توافق على تحمل مسؤولية أي ضرر يحدث لجهاز التلفزيون أو فقدان البيانات الذي قد ينتج عن استخدامه."</string>
diff --git a/packages/PackageInstaller/res/values-bs/strings.xml b/packages/PackageInstaller/res/values-bs/strings.xml
index d2bf501b1e9b..edd82bcd8b9e 100644
--- a/packages/PackageInstaller/res/values-bs/strings.xml
+++ b/packages/PackageInstaller/res/values-bs/strings.xml
@@ -81,9 +81,9 @@
<string name="wear_not_allowed_dlg_text" msgid="704615521550939237">"Instaliranje/deinstaliranje nije podržano na Wearu."</string>
<string name="message_staging" msgid="8032722385658438567">"Pripremanje aplikacije…"</string>
<string name="app_name_unknown" msgid="6881210203354323926">"Nepoznato"</string>
- <string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"Radi vaše sigurnosti, tabletu trenutno nije dozvoljeno da instalira nepoznate aplikacije iz ovog izvora. Ovo možete promijeniti u Postavkama."</string>
- <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"Radi vaše sigurnosti, TV-u trenutno nije dozvoljeno da instalira nepoznate aplikacije iz ovog izvora. Ovo možete promijeniti u Postavkama."</string>
- <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Radi vaše sigurnosti, telefonu trenutno nije dozvoljeno da instalira nepoznate aplikacije iz ovog izvora. Ovo možete promijeniti u Postavkama."</string>
+ <string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"Radi vaše sigurnosti tabletu trenutno nije dozvoljeno da instalira nepoznate aplikacije iz ovog izvora. Ovo možete promijeniti u Postavkama."</string>
+ <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"Radi vaše sigurnosti TV-u trenutno nije dozvoljeno da instalira nepoznate aplikacije iz ovog izvora. Ovo možete promijeniti u Postavkama."</string>
+ <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Radi vaše sigurnosti telefonu trenutno nije dozvoljeno da instalira nepoznate aplikacije iz ovog izvora. Ovo možete promijeniti u Postavkama."</string>
<string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Vaši podaci na telefonu i vaši lični podaci izloženiji su napadima nepoznatih aplikacija. Instaliranjem ove aplikacije, prihvatate odgovornost za bilo kakvu štetu na telefonu ili gubitak podataka do kojih može doći korištenjem aplikacije."</string>
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Vaši podaci na tabletu i vaši lični podaci izloženiji su napadima nepoznatih aplikacija. Instaliranjem ove aplikacije, prihvatate odgovornost za bilo kakvu štetu na tabletu ili gubitak podataka do kojih može doći korištenjem aplikacije."</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Vaši podaci na TV-u i vaši lični podaci izloženiji su napadima nepoznatih aplikacija. Instaliranjem ove aplikacije, prihvatate odgovornost za bilo kakvu štetu na TV-u ili gubitak podataka do kojih može doći korištenjem aplikacije."</string>
diff --git a/packages/PackageInstaller/res/values-es/strings.xml b/packages/PackageInstaller/res/values-es/strings.xml
index 1b000c268a8a..37599c4a63db 100644
--- a/packages/PackageInstaller/res/values-es/strings.xml
+++ b/packages/PackageInstaller/res/values-es/strings.xml
@@ -23,7 +23,7 @@
<string name="cancel" msgid="1018267193425558088">"Cancelar"</string>
<string name="installing" msgid="4921993079741206516">"Instalando…"</string>
<string name="installing_app" msgid="1165095864863849422">"Instalando <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>…"</string>
- <string name="install_done" msgid="5987363587661783896">"Se ha instalado la aplicación."</string>
+ <string name="install_done" msgid="5987363587661783896">"Aplicación instalada."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"¿Quieres instalar esta aplicación?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"¿Quieres actualizar esta aplicación?"</string>
<string name="install_failed" msgid="5777824004474125469">"No se ha instalado la aplicación."</string>
@@ -81,9 +81,9 @@
<string name="wear_not_allowed_dlg_text" msgid="704615521550939237">"Las acciones de instalar y desinstalar no pueden realizarse en Wear."</string>
<string name="message_staging" msgid="8032722385658438567">"Preparando aplicación…"</string>
<string name="app_name_unknown" msgid="6881210203354323926">"Desconocida"</string>
- <string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"Por motivos de seguridad, de momento tu tablet no puede instalar aplicaciones desconocidas de esta fuente. Puedes cambiarlo en Ajustes."</string>
- <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"Por motivos de seguridad, de momento tu televisor no puede instalar aplicaciones desconocidas de esta fuente. Puedes cambiarlo en Ajustes."</string>
- <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Por motivos de seguridad, de momento tu teléfono no puede instalar aplicaciones desconocidas de esta fuente. Puedes cambiarlo en Ajustes."</string>
+ <string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"Por tu seguridad, de momento tu tablet no puede instalar aplicaciones desconocidas de esta fuente. Puedes cambiarlo en Ajustes."</string>
+ <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"Por tu seguridad, de momento tu televisor no puede instalar aplicaciones desconocidas de esta fuente. Puedes cambiarlo en Ajustes."</string>
+ <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Por tu seguridad, de momento tu teléfono no puede instalar aplicaciones desconocidas de esta fuente. Puedes cambiarlo en Ajustes."</string>
<string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Tu teléfono y tus datos personales son más vulnerables a los ataques de aplicaciones desconocidas. Al instalar esta aplicación, aceptas ser responsable de cualquier daño que sufra tu teléfono o la pérdida de datos que se pueda derivar de su uso."</string>
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Tu tablet y tus datos personales son más vulnerables a los ataques de aplicaciones desconocidas. Al instalar esta aplicación, aceptas ser responsable de cualquier daño que sufra tu tablet o la pérdida de datos que se pueda derivar de su uso."</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Tu TV y tus datos personales son más vulnerables a los ataques de aplicaciones desconocidas. Al instalar esta aplicación, aceptas ser responsable de cualquier daño que sufra tu TV o la pérdida de datos que se pueda derivar de su uso."</string>
diff --git a/packages/PackageInstaller/res/values-gl/strings.xml b/packages/PackageInstaller/res/values-gl/strings.xml
index 720a3cbb4362..a6454da20358 100644
--- a/packages/PackageInstaller/res/values-gl/strings.xml
+++ b/packages/PackageInstaller/res/values-gl/strings.xml
@@ -23,7 +23,7 @@
<string name="cancel" msgid="1018267193425558088">"Cancelar"</string>
<string name="installing" msgid="4921993079741206516">"Instalando…"</string>
<string name="installing_app" msgid="1165095864863849422">"Instalando <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>…"</string>
- <string name="install_done" msgid="5987363587661783896">"Instalouse a aplicación"</string>
+ <string name="install_done" msgid="5987363587661783896">"Instalouse a aplicación."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Queres instalar esta aplicación?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Queres actualizar esta aplicación?"</string>
<string name="install_failed" msgid="5777824004474125469">"Non se instalou a aplicación"</string>
diff --git a/packages/PackageInstaller/res/values-hi/strings.xml b/packages/PackageInstaller/res/values-hi/strings.xml
index 5981ce966ebb..64df1bb15fd9 100644
--- a/packages/PackageInstaller/res/values-hi/strings.xml
+++ b/packages/PackageInstaller/res/values-hi/strings.xml
@@ -24,7 +24,7 @@
<string name="installing" msgid="4921993079741206516">"इंस्टॉल हो रहा है..."</string>
<string name="installing_app" msgid="1165095864863849422">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> इंस्टॉल हो रहा है…"</string>
<string name="install_done" msgid="5987363587661783896">"ऐप्लिकेशन इंस्‍टॉल हो गया."</string>
- <string name="install_confirm_question" msgid="7663733664476363311">"क्या आप इस ऐप्लिकेशन को इंस्टॉल करना चाहते हैं?"</string>
+ <string name="install_confirm_question" msgid="7663733664476363311">"क्या आपको यह ऐप्लिकेशन इंस्टॉल करना है?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"क्या आप इस ऐप्लिकेशन को अपडेट करना चाहते हैं?"</string>
<string name="install_failed" msgid="5777824004474125469">"ऐप्लिकेशन इंस्‍टॉल नहीं हुआ."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"पैकेज को इंस्टॉल होने से ब्लॉक किया हुआ है."</string>
@@ -83,7 +83,7 @@
<string name="app_name_unknown" msgid="6881210203354323926">"अनजान"</string>
<string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"आपकी सुरक्षा के लिए, आपके टैबलेट को फ़िलहाल इस स्रोत से अनजान ऐप्लिकेशन इंस्टॉल करने की अनुमति नहीं है. आप \'सेटिंग\' में जाकर इसे बदल सकते हैं."</string>
<string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"आपकी सुरक्षा के लिए, आपके टीवी को फ़िलहाल इस स्रोत से अनजान ऐप्लिकेशन इंस्टॉल करने की अनुमति नहीं है. आप \'सेटिंग\' में जाकर इसे बदल सकते हैं."</string>
- <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"आपकी सुरक्षा के लिए, आपके फ़ोन को फ़िलहाल इस स्रोत से अनजान ऐप्लिकेशन इंस्टॉल करने की अनुमति नहीं है. आप \'सेटिंग\' में जाकर इसे बदल सकते हैं."</string>
+ <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"आपकी सुरक्षा के लिए, आपके फ़ोन को फ़िलहाल इस सोर्स से अनजान ऐप्लिकेशन इंस्टॉल करने की अनुमति नहीं है. सेटिंग में जाकर इसे बदला जा सकता है."</string>
<string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"आपका फ़ोन और निजी डेटा अनजान ऐप्लिकेशन के हमले को लेकर ज़्यादा संवेदनशील हैं. इस ऐप्लिकेशन को इंस्टॉल करके, आप सहमति देते हैं कि इसके इस्तेमाल के चलते आपके फ़ोन को होने वाले किसी भी नुकसान या डेटा के मिट जाने पर, आप ज़िम्मेदार होंगे."</string>
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"आपका टैबलेट और निजी डेटा अनजान ऐप्लिकेशन के हमले को लेकर ज़्यादा संवेदनशील हैं. इस ऐप्लिकेशन को इंस्टॉल करके, आप सहमति देते हैं कि इसके इस्तेमाल के चलते आपके टैबलेट को होने वाले किसी भी नुकसान या डेटा के मिट जाने पर, आप ज़िम्मेदार होंगे."</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"आपका टीवी और निजी डेटा अनजान ऐप्लिकेशन के हमले को लेकर ज़्यादा संवेदनशील हैं. इस ऐप्लिकेशन को इंस्टॉल करके, आप सहमति देते हैं कि इसके इस्तेमाल के चलते आपके टीवी को होने वाले किसी भी नुकसान या डेटा के मिट जाने पर, आप ज़िम्मेदार होंगे."</string>
diff --git a/packages/PackageInstaller/res/values-ja/strings.xml b/packages/PackageInstaller/res/values-ja/strings.xml
index 8ddc87c0c738..e2a5aaa24690 100644
--- a/packages/PackageInstaller/res/values-ja/strings.xml
+++ b/packages/PackageInstaller/res/values-ja/strings.xml
@@ -84,9 +84,9 @@
<string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"セキュリティ上の理由から、お使いのタブレットでは現在、この提供元からの不明なアプリをインストールすることはできません。これは [設定] で変更できます。"</string>
<string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"セキュリティ上の理由から、お使いのテレビでは現在、この提供元からの不明なアプリをインストールすることはできません。これは [設定] で変更できます。"</string>
<string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"セキュリティ上の理由から、お使いのスマートフォンでは現在、この提供元からの不明なアプリをインストールすることはできません。これは [設定] で変更できます。"</string>
- <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"不明なアプリをインストールするとスマートフォンや個人データが攻撃を受ける可能性が高くなります。このアプリをインストールすることにより、アプリの使用により生じる可能性があるスマートフォンへの損害やデータの損失について、ユーザーご自身が単独で責任を負うことに同意するものとします。"</string>
- <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"不明なアプリをインストールするとタブレットや個人データが攻撃を受ける可能性が高くなります。このアプリをインストールすることにより、アプリの使用により生じる可能性があるタブレットへの損害やデータの損失について、ユーザーご自身が単独で責任を負うことに同意するものとします。"</string>
- <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"不明なアプリをインストールするとテレビや個人データが攻撃を受ける可能性が高くなります。このアプリをインストールすることにより、アプリの使用により生じる可能性があるテレビへの損害やデータの損失について、ユーザーご自身が単独で責任を負うことに同意するものとします。"</string>
+ <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"不明なアプリをインストールするとスマートフォンや個人データの侵害に対する安全性が低下します。このアプリをインストールすることで、アプリの使用により生じる可能性があるスマートフォンへの侵害やデータの損失について、ユーザーご自身が単独で責任を負うことに同意することになります。"</string>
+ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"不明なアプリをインストールするとタブレットや個人データの侵害に対する安全性が低下します。このアプリをインストールすることで、アプリの使用により生じる可能性があるタブレットへの侵害やデータの損失について、ユーザーご自身が単独で責任を負うことに同意することになります。"</string>
+ <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"不明なアプリをインストールするとテレビや個人データの侵害に対する安全性が低下します。このアプリをインストールすることで、アプリの使用により生じる可能性があるテレビへの侵害やデータの損失について、ユーザーご自身が単独で責任を負うことに同意することになります。"</string>
<string name="anonymous_source_continue" msgid="4375745439457209366">"次へ"</string>
<string name="external_sources_settings" msgid="4046964413071713807">"設定"</string>
<string name="wear_app_channel" msgid="1960809674709107850">"Wearアプリ インストール/アンインストール"</string>
diff --git a/packages/PackageInstaller/res/values-km/strings.xml b/packages/PackageInstaller/res/values-km/strings.xml
index 8306b4821e7e..06c5ea2be671 100644
--- a/packages/PackageInstaller/res/values-km/strings.xml
+++ b/packages/PackageInstaller/res/values-km/strings.xml
@@ -83,7 +83,7 @@
<string name="app_name_unknown" msgid="6881210203354323926">"មិនស្គាល់"</string>
<string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"ដើម្បីសុវត្ថិភាពរបស់អ្នក បច្ចុប្បន្នទូរទស្សន៍របស់អ្នកមិនត្រូវបានអនុញ្ញាតឱ្យដំឡើងកម្មវិធីដែលមិនស្គាល់ពីប្រភពនេះទេ។ អ្នកអាច​ប្ដូរវាបាន​នៅក្នុងការ​កំណត់។"</string>
<string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"ដើម្បីសុវត្ថិភាពរបស់អ្នក បច្ចុប្បន្នទូរទស្សន៍របស់អ្នកមិនត្រូវបានអនុញ្ញាតឱ្យដំឡើងកម្មវិធីដែលមិនស្គាល់ពីប្រភពនេះទេ។ អ្នកអាច​ប្ដូរវាបាន​នៅក្នុងការ​កំណត់។"</string>
- <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"ដើម្បីសុវត្ថិភាពរបស់អ្នក បច្ចុប្បន្នទូរទស្សន៍របស់អ្នកមិនត្រូវបានអនុញ្ញាតឱ្យដំឡើងកម្មវិធីដែលមិនស្គាល់ពីប្រភពនេះទេ។ អ្នកអាច​ប្ដូរវាបាន​នៅក្នុងការ​កំណត់។"</string>
+ <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"ដើម្បីសុវត្ថិភាពរបស់អ្នក បច្ចុប្បន្នទូរសព្ទរបស់អ្នកមិនត្រូវបានអនុញ្ញាតឱ្យដំឡើងកម្មវិធីដែលមិនស្គាល់ពីប្រភពនេះទេ។ អ្នកអាច​ប្ដូរវាបាន​នៅក្នុងការ​កំណត់។"</string>
<string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"ទូរសព្ទ និងទិន្នន័យផ្ទាល់ខ្លួនរបស់អ្នកកាន់តែងាយនឹងរងគ្រោះពីការវាយប្រហារពីកម្មវិធីដែលមិនស្គាល់។ ប្រសិនបើដំឡើងកម្មវិធីនេះ អ្នកយល់ព្រមថា អ្នកទទួលខុសត្រូវលើការខូចខាតទាំងឡាយមកលើទូរសព្ទរបស់អ្នក ឬការបាត់បង់ទិន្នន័យ ដែលអាចបណ្ដាលមកពីការប្រើប្រាស់កម្មវិធីនេះ។"</string>
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"ថេប្លេត និងទិន្នន័យផ្ទាល់ខ្លួនរបស់អ្នកងាយនឹងរងគ្រោះពីការវាយប្រហារពីកម្មវិធីដែលមិនស្គាល់។ ប្រសិនបើដំឡើងកម្មវិធីនេះ មានន័យថាអ្នកទទួលខុសត្រូវលើការខូចខាតទាំងឡាយចំពោះថេប្លេត ឬការបាត់បង់ទិន្នន័យរបស់អ្នក ដែលអាចបណ្ដាលមកពីការប្រើប្រាស់កម្មវិធីនេះ។"</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"ទូរទស្សន៍ និងទិន្នន័យផ្ទាល់ខ្លួនរបស់អ្នកងាយនឹងរងគ្រោះពីការវាយប្រហារពីកម្មវិធីដែលមិនស្គាល់។ ប្រសិនបើដំឡើងកម្មវិធីនេះ មានន័យថាអ្នកទទួលខុសត្រូវលើការខូចខាតទាំងឡាយចំពោះទូរទស្សន៍ ឬការបាត់បង់ទិន្នន័យរបស់អ្នក ដែលអាចបណ្ដាលមកពីការប្រើប្រាស់កម្មវិធីនេះ។"</string>
diff --git a/packages/PackageInstaller/res/values-ky/strings.xml b/packages/PackageInstaller/res/values-ky/strings.xml
index 5adfd2b42692..2684fd969880 100644
--- a/packages/PackageInstaller/res/values-ky/strings.xml
+++ b/packages/PackageInstaller/res/values-ky/strings.xml
@@ -81,9 +81,9 @@
<string name="wear_not_allowed_dlg_text" msgid="704615521550939237">"Орнотуу/чыгарып салуу аракеттери Android Wear\'де колдоого алынбайт."</string>
<string name="message_staging" msgid="8032722385658438567">"Күтө туруңуз…"</string>
<string name="app_name_unknown" msgid="6881210203354323926">"Белгисиз"</string>
- <string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"Коопсуздукту сактоо максатында, азырынча планшетиңизге бул булактан колдонмолорду орнотууга уруксат жок. Муну Жөндөөлөрдөн өзгөртсөңүз болот."</string>
- <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"Коопсуздукту сактоо максатында, азырынча сыналгыңызга бул булактан колдонмолорду орнотууга уруксат жок. Муну Жөндөөлөрдөн өзгөртсөңүз болот."</string>
- <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Коопсуздукту сактоо максатында, азырынча телефонуңузга бул булактан колдонмолорду орнотууга уруксат жок. Муну Жөндөөлөрдөн өзгөртсөңүз болот."</string>
+ <string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"Коопсуздук максатында, планшетиңизге бул булактан колдонмолорду орнотууга болбойт. Бул параметрди каалаган убакта жөндөөлөрдөн өзгөртө аласыз."</string>
+ <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"Коопсуздук максатында, сыналгыңызга бул булактан колдонмолорду орнотууга болбойт. Бул параметрди каалаган убакта жөндөөлөрдөн өзгөртө аласыз."</string>
+ <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Коопсуздук максатында, телефонуңузга бул булактан колдонмолорду орнотууга болбойт. Бул параметрди каалаган убакта жөндөөлөрдөн өзгөртө аласыз."</string>
<string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Телефонуңуз жана жеке дайын-даректериңиз белгисиз колдонмолордон зыян тартып калышы мүмкүн. Бул колдонмону орнотуп, аны пайдалануудан улам телефонуңузга кандайдыр бир зыян келтирилсе же дайын-даректериңизды жоготуп алсаңыз, өзүңүз жооптуу болосуз."</string>
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Планшетиңиз жана жеке дайын-даректериңиз белгисиз колдонмолордон зыян тартып калышы мүмкүн. Бул колдонмону орнотуп, аны пайдалануудан улам планшетиңизге кандайдыр бир зыян келтирилсе же дайын-даректериңизды жоготуп алсаңыз, өзүңүз жооптуу болосуз."</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Сыналгыңыз жана жеке дайын-даректериңиз белгисиз колдонмолордон зыян тартып калышы мүмкүн. Бул колдонмону орнотуп, аны пайдалануудан улам сыналгыңызга кандайдыр бир зыян келтирилсе же дайын-даректериңизды жоготуп алсаңыз, өзүңүз жооптуу болосуз."</string>
diff --git a/packages/PackageInstaller/res/values-mr/strings.xml b/packages/PackageInstaller/res/values-mr/strings.xml
index 42a96765ca66..40bb6802e2d6 100644
--- a/packages/PackageInstaller/res/values-mr/strings.xml
+++ b/packages/PackageInstaller/res/values-mr/strings.xml
@@ -83,7 +83,7 @@
<string name="app_name_unknown" msgid="6881210203354323926">"अज्ञात"</string>
<string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"तुमच्या सुरक्षिततेसाठी, तुमच्या टॅबलेटला सध्या या स्रोतावरील अज्ञात अ‍ॅप्स इंस्टॉल करण्याची अनुमती नाही. तुम्ही हे सेटिंग्‍ज मध्‍ये बदलू शकता."</string>
<string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"तुमच्या सुरक्षिततेसाठी, तुमच्या टीव्हीला सध्या या स्रोतावरील अज्ञात अ‍ॅप्स इंस्टॉल करण्याची अनुमती नाही. तुम्ही हे सेटिंग्‍ज मध्‍ये बदलू शकता."</string>
- <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"तुमच्या सुरक्षिततेसाठी, तुमच्या फोनला सध्या या स्रोतावरील अज्ञात अ‍ॅप्स इंस्टॉल करण्याची अनुमती नाही. तुम्ही हे सेटिंग्‍ज मध्‍ये बदलू शकता."</string>
+ <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"तुमच्या सुरक्षेसाठी, तुमच्या फोनला सध्या या स्रोतावरील अज्ञात अ‍ॅप्स इंस्टॉल करण्याची अनुमती नाही. तुम्ही हे सेटिंग्‍ज मध्‍ये बदलू शकता."</string>
<string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"तुमचा फोन आणि वैयक्तिक डेटा अज्ञात अ‍ॅप्‍सकडून होणार्‍या अटॅकमुळे अधिक असुरक्षित आहे. हे अ‍ॅप इंस्टॉल करून, तुम्‍ही सहमती देता की ते वापरल्‍याने होणार्‍या तुमच्‍या फोनचे कोणत्‍याही प्रकारे होणारे नुकसान किंवा डेटा हानीसाठी तुम्‍ही जबाबदार आहात."</string>
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"तुमचा टॅबलेट आणि वैयक्तिक डेटा अज्ञात अ‍ॅप्‍सकडून होणार्‍या अटॅकमुळे अधिक असुरक्षित आहे. हे अ‍ॅप इंस्टॉल करून, तुम्‍ही सहमती देता की ते वापरल्‍याने तुमच्‍या टॅबलेटचे कोणत्‍याही प्रकारे होणारे नुकसान किंवा डेटा हानीसाठी तुम्‍ही जबाबदार आहात."</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"तुमचा टीव्‍ही आणि वैयक्तिक डेटा अज्ञात अ‍ॅप्‍सकडून होणार्‍या अटॅकमुळे अधिक असुरक्षित आहे. हे अ‍ॅप इंस्टॉल करून, तुम्ही सहमती देता की ते वापरल्‍याने तुमच्‍या टीव्‍हीचे कोणत्‍याही प्रकारे होणारे नुकसान किंवा डेटा हानीसाठी तुम्‍ही जबाबदार आहात."</string>
diff --git a/packages/PackageInstaller/res/values-my/strings.xml b/packages/PackageInstaller/res/values-my/strings.xml
index d6e72d6cb415..7b632d004a1f 100644
--- a/packages/PackageInstaller/res/values-my/strings.xml
+++ b/packages/PackageInstaller/res/values-my/strings.xml
@@ -23,7 +23,7 @@
<string name="cancel" msgid="1018267193425558088">"မလုပ်တော့"</string>
<string name="installing" msgid="4921993079741206516">"ထည့်သွင်းနေသည်…"</string>
<string name="installing_app" msgid="1165095864863849422">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ကို ထည့်သွင်းနေသည်…"</string>
- <string name="install_done" msgid="5987363587661783896">"အက်ပ်ထည့်သွင်းပြီးပါပြီ"</string>
+ <string name="install_done" msgid="5987363587661783896">"အက်ပ်ထည့်သွင်းပြီးပါပြီ။"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ဤအက်ပ်ကို ထည့်သွင်းလိုသလား။"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ဤအက်ပ်ကို အပ်ဒိတ်လုပ်လိုသလား။"</string>
<string name="install_failed" msgid="5777824004474125469">"အက်ပ်မထည့်သွင်းရသေးပါ"</string>
@@ -83,7 +83,7 @@
<string name="app_name_unknown" msgid="6881210203354323926">"အမည်မသိ"</string>
<string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"လုံခြုံရေးအရ ဤရင်းမြစ်မှရယူထားသည့် အမျိုးအမည်မသိသောအက်ပ်များကို သင့်တက်ဘလက်တွင် လောလောဆယ် ထည့်သွင်းခွင့်မရှိပါ။ ၎င်းကို ‘ဆက်တင်များ’ တွင် ပြောင်းနိုင်ပါသည်။"</string>
<string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"လုံခြုံရေးအရ ဤရင်းမြစ်မှရယူထားသည့် အမျိုးအမည်မသိသောအက်ပ်များကို သင့် TV တွင် လောလောဆယ် ထည့်သွင်းခွင့်မရှိပါ။ ၎င်းကို ‘ဆက်တင်များ’ တွင် ပြောင်းနိုင်ပါသည်။"</string>
- <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"လုံခြုံရေးအရ ဤရင်းမြစ်မှရယူထားသည့် အမျိုးအမည်မသိသောအက်ပ်များကို သင့်ဖုန်းတွင် လောလောဆယ် ထည့်သွင်းခွင့်မရှိပါ။ ၎င်းကို ‘ဆက်တင်များ’ တွင် ပြောင်းနိုင်ပါသည်။"</string>
+ <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"ဤရင်းမြစ်မှရယူထားသည့် အမျိုးအမည်မသိသောအက်ပ်များကို သင့်လုံခြုံရေးအတွက် သင့်ဖုန်းတွင် လောလောဆယ် ထည့်သွင်းခွင့်ပြုမထားပါ။ ၎င်းကို ‘ဆက်တင်များ’ တွင် ပြောင်းနိုင်ပါသည်။"</string>
<string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"သင်၏ဖုန်းနှင့် ကိုယ်ရေးကိုယ်တာ အချက်အလက်များသည် အမျိုးအမည် မသိသောအက်ပ်များ၏ တိုက်ခိုက်ခြင်းကို ပိုမိုခံရနိုင်ပါသည်။ ဤအက်ပ်ကို ထည့်သွင်းအသုံးပြုခြင်းအားဖြင့် ဖြစ်ပေါ်လာနိုင်သော ဖုန်းပျက်စီးမှု သို့မဟုတ် ဒေတာဆုံးရှုံးမှုများအတွက် သင့်ထံ၌သာ တာဝန်ရှိကြောင်း သဘောတူရာရောက်ပါသည်။"</string>
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"သင်၏ တက်ဘလက်နှင့် ကိုယ်ရေးကိုယ်တာ အချက်အလက်များသည် အမျိုးအမည် မသိသောအက်ပ်များ၏ တိုက်ခိုက်ခြင်းကို ပိုမိုခံရနိုင်ပါသည်။ ဤအက်ပ်ကို ထည့်သွင်းအသုံးပြုခြင်းအားဖြင့် ဖြစ်ပေါ်လာနိုင်သော တက်ဘလက်ပျက်စီးမှု သို့မဟုတ် ဒေတာဆုံးရှုံးမှုများအတွက် သင့်ထံ၌သာ တာဝန်ရှိကြောင်း သဘောတူရာရောက်ပါသည်။"</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"သင်၏ TV နှင့် ကိုယ်ရေးကိုယ်တာ အချက်အလက်များသည် အမျိုးအမည် မသိသောအက်ပ်များ၏ တိုက်ခိုက်ခြင်းကို ပိုမိုခံရနိုင်ပါသည်။ ဤအက်ပ်ကို ထည့်သွင်းအသုံးပြုခြင်းအားဖြင့် ဖြစ်ပေါ်လာနိုင်သော TV ပျက်စီးမှု သို့မဟုတ် ဒေတာဆုံးရှုံးမှုများအတွက် သင့်ထံ၌သာ တာဝန်ရှိကြောင်း သဘောတူရာရောက်ပါသည်။"</string>
diff --git a/packages/PackageInstaller/res/values-ne/strings.xml b/packages/PackageInstaller/res/values-ne/strings.xml
index 24303d16e2a7..50422d71a5b1 100644
--- a/packages/PackageInstaller/res/values-ne/strings.xml
+++ b/packages/PackageInstaller/res/values-ne/strings.xml
@@ -21,9 +21,9 @@
<string name="update" msgid="3932142540719227615">"अपडेट गर्नुहोस्"</string>
<string name="done" msgid="6632441120016885253">"सम्पन्न भयो"</string>
<string name="cancel" msgid="1018267193425558088">"रद्द गर्नुहोस्"</string>
- <string name="installing" msgid="4921993079741206516">"स्थापना गर्दै…"</string>
- <string name="installing_app" msgid="1165095864863849422">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> स्थापना गर्दै…"</string>
- <string name="install_done" msgid="5987363587661783896">"एप स्थापना गरियो।"</string>
+ <string name="installing" msgid="4921993079741206516">"इन्स्टल गरिँदै छ"</string>
+ <string name="installing_app" msgid="1165095864863849422">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> इन्स्टल गरिँदै छ"</string>
+ <string name="install_done" msgid="5987363587661783896">"एप इन्स्टल गरियो।"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"तपाईं यो एप इन्स्टल गर्न चाहनुहुन्छ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"तपाईं यो एप अपडेट गर्न चाहनुहुन्छ?"</string>
<string name="install_failed" msgid="5777824004474125469">"एप स्थापना गरिएन।"</string>
diff --git a/packages/PackageInstaller/res/values-nl/strings.xml b/packages/PackageInstaller/res/values-nl/strings.xml
index 8afe5dbb310e..53a9a00724f1 100644
--- a/packages/PackageInstaller/res/values-nl/strings.xml
+++ b/packages/PackageInstaller/res/values-nl/strings.xml
@@ -83,7 +83,7 @@
<string name="app_name_unknown" msgid="6881210203354323926">"Onbekend"</string>
<string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"Uit veiligheidsoverwegingen heeft je tablet momenteel geen toestemming om onbekende apps van deze bron te installeren. Je kunt dit wijzigen via Instellingen."</string>
<string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"Uit veiligheidsoverwegingen heeft je tv momenteel geen toestemming om onbekende apps van deze bron te installeren. Je kunt dit wijzigen via Instellingen."</string>
- <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Uit veiligheidsoverwegingen heeft je telefoon momenteel geen toestemming op onbekende apps van deze bron te installeren. Je kunt dit wijzigen via Instellingen."</string>
+ <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Uit veiligheidsoverwegingen heeft je telefoon momenteel geen toestemming om onbekende apps van deze bron te installeren. Je kunt dit wijzigen via Instellingen."</string>
<string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Je telefoon en persoonsgegevens zijn kwetsbaarder voor aanvallen door onbekende apps. Als je deze app installeert, ga je ermee akkoord dat je verantwoordelijk bent voor eventuele schade aan je telefoon of gegevensverlies als gevolg van het gebruik van de app."</string>
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Je tablet en persoonsgegevens zijn kwetsbaarder voor aanvallen door onbekende apps. Als je deze app installeert, ga je ermee akkoord dat je verantwoordelijk bent voor eventuele schade aan je tablet of gegevensverlies als gevolg van het gebruik van de app."</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Je tv en persoonsgegevens zijn kwetsbaarder voor aanvallen door onbekende apps. Als je deze app installeert, ga je ermee akkoord dat je verantwoordelijk bent voor eventuele schade aan je tv of gegevensverlies als gevolg van het gebruik van de app."</string>
diff --git a/packages/PackageInstaller/res/values-or/strings.xml b/packages/PackageInstaller/res/values-or/strings.xml
index ca01d7f839b8..4bc5bec46543 100644
--- a/packages/PackageInstaller/res/values-or/strings.xml
+++ b/packages/PackageInstaller/res/values-or/strings.xml
@@ -23,7 +23,7 @@
<string name="cancel" msgid="1018267193425558088">"ବାତିଲ୍ କରନ୍ତୁ"</string>
<string name="installing" msgid="4921993079741206516">"ଇନଷ୍ଟଲ୍‌ କରାଯାଉଛି…"</string>
<string name="installing_app" msgid="1165095864863849422">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ଇନଷ୍ଟଲ୍‌ କରାଯାଉଛି…"</string>
- <string name="install_done" msgid="5987363587661783896">"ଆପ୍‍ ଇନଷ୍ଟଲ୍‌ ହୋଇଗଲା।"</string>
+ <string name="install_done" msgid="5987363587661783896">"ଆପ ଇନଷ୍ଟଲ ହୋଇଗଲା।"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ଆପଣ ଏହି ଆପକୁ ଇନଷ୍ଟଲ୍ କରିବା ପାଇଁ ଚାହୁଁଛନ୍ତି କି?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ଆପଣ ଏହି ଆପକୁ ଅପଡେଟ୍ କରିବା ପାଇଁ ଚାହୁଁଛନ୍ତି କି?"</string>
<string name="install_failed" msgid="5777824004474125469">"ଆପ୍‍ ଇନଷ୍ଟଲ୍‌ ହୋଇନାହିଁ।"</string>
diff --git a/packages/PackageInstaller/res/values-pa/strings.xml b/packages/PackageInstaller/res/values-pa/strings.xml
index d5b85738314e..05bf12791224 100644
--- a/packages/PackageInstaller/res/values-pa/strings.xml
+++ b/packages/PackageInstaller/res/values-pa/strings.xml
@@ -83,7 +83,7 @@
<string name="app_name_unknown" msgid="6881210203354323926">"ਅਗਿਆਤ"</string>
<string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"ਤੁਹਾਡੀ ਸੁਰੱਖਿਆ ਲਈ, ਫ਼ਿਲਹਾਲ ਤੁਹਾਡੇ ਟੈਬਲੈੱਟ ਨੂੰ ਇਸ ਸਰੋਤ ਤੋਂ ਅਗਿਆਤ ਐਪਾਂ ਸਥਾਪਤ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ। ਤੁਸੀਂ ਇਸ ਨੂੰ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਬਦਲ ਸਕਦੇ ਹੋ।"</string>
<string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"ਤੁਹਾਡੀ ਸੁਰੱਖਿਆ ਲਈ, ਫ਼ਿਲਹਾਲ ਤੁਹਾਡੇ ਟੀਵੀ ਨੂੰ ਇਸ ਸਰੋਤ ਤੋਂ ਅਗਿਆਤ ਐਪਾਂ ਸਥਾਪਤ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ। ਤੁਸੀਂ ਇਸ ਨੂੰ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਬਦਲ ਸਕਦੇ ਹੋ।"</string>
- <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"ਤੁਹਾਡੀ ਸੁਰੱਖਿਆ ਲਈ, ਫ਼ਿਲਹਾਲ ਤੁਹਾਡੇ ਫ਼ੋਨ ਨੂੰ ਇਸ ਸਰੋਤ ਤੋਂ ਅਗਿਆਤ ਐਪਾਂ ਸਥਾਪਤ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ। ਤੁਸੀਂ ਇਸ ਨੂੰ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਬਦਲ ਸਕਦੇ ਹੋ।"</string>
+ <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"ਤੁਹਾਡੀ ਸੁਰੱਖਿਆ ਲਈ, ਫ਼ਿਲਹਾਲ ਤੁਹਾਡੇ ਫ਼ੋਨ ਨੂੰ ਇਸ ਸਰੋਤ ਤੋਂ ਅਗਿਆਤ ਐਪਾਂ ਸਥਾਪਤ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਹੈ। ਤੁਸੀਂ ਇਸ ਨੂੰ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਬਦਲ ਸਕਦੇ ਹੋ।"</string>
<string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"ਅਗਿਆਤ ਐਪਾਂ ਤੋਂ ਹੋਣ ਵਾਲੇ ਹਮਲਿਆਂ ਕਰਕੇ ਤੁਹਾਡੇ ਫ਼ੋਨ ਅਤੇ ਨਿੱਜੀ ਡਾਟੇ ਨਾਲ ਛੇੜਛਾੜ ਹੋ ਸਕਦੀ ਹੈ। ਇਹ ਐਪ ਸਥਾਪਤ ਕਰਕੇ, ਤੁਸੀਂ ਸਹਿਮਤੀ ਦਿੰਦੇ ਹੋ ਕਿ ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਹੋਣ ਵਾਲੇ ਕਿਸੇ ਵੀ ਨੁਕਸਾਨ ਜਾਂ ਡਾਟੇ ਦੀ ਹਾਨੀ ਲਈ ਤੁਸੀਂ ਜ਼ਿੰਮੇਵਾਰ ਹੋ ਜੋ ਸ਼ਾਇਦ ਇਸ ਐਪ ਨੂੰ ਵਰਤਣ ਦੇ ਨਤੀਜੇ ਵਜੋਂ ਹੋ ਸਕਦਾ ਹੈ।"</string>
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"ਤੁਹਾਡਾ ਟੈਬਲੈੱਟ ਅਤੇ ਨਿੱਜੀ ਡਾਟਾ ਅਗਿਆਤ ਐਪਾਂ ਤੋਂ ਹਮਲੇ ਪ੍ਰਤੀ ਵਧੇਰੇ ਵਿੰਨਣਸ਼ੀਲ ਹਨ। ਇਹ ਐਪ ਸਥਾਪਤ ਕਰਕੇ, ਤੁਸੀਂ ਸਹਿਮਤੀ ਦਿੰਦੇ ਹੋ ਕਿ ਆਪਣੇ ਟੈਬਲੈੱਟ ਨੂੰ ਹੋਣ ਵਾਲੇ ਕਿਸੇ ਵੀ ਨੁਕਸਾਨ ਜਾਂ ਡਾਟੇ ਦੀ ਹਾਨੀ ਲਈ ਤੁਸੀਂ ਜ਼ੁੰਮੇਵਾਰ ਹੋ ਜੋ ਸ਼ਾਇਦ ਇਸ ਐਪ ਨੂੰ ਵਰਤਣ ਦੇ ਨਤੀਜੇ ਵਜੋਂ ਹੋ ਸਕਦਾ ਹੈ।"</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"ਤੁਹਾਡਾ ਟੀਵੀ ਅਤੇ ਨਿੱਜੀ ਡਾਟਾ ਅਗਿਆਤ ਐਪਾਂ ਤੋਂ ਹਮਲੇ ਪ੍ਰਤੀ ਵਧੇਰੇ ਵਿੰਨਣਸ਼ੀਲ ਹਨ। ਇਹ ਐਪ ਸਥਾਪਤ ਕਰਕੇ, ਤੁਸੀਂ ਸਹਿਮਤੀ ਦਿੰਦੇ ਹੋ ਕਿ ਆਪਣੇ ਟੀਵੀ ਨੂੰ ਹੋਣ ਵਾਲੇ ਕਿਸੇ ਵੀ ਨੁਕਸਾਨ ਜਾਂ ਡਾਟੇ ਦੀ ਹਾਨੀ ਲਈ ਤੁਸੀਂ ਜ਼ੁੰਮੇਵਾਰ ਹੋ ਜੋ ਸ਼ਾਇਦ ਇਸ ਐਪ ਨੂੰ ਵਰਤਣ ਦੇ ਨਤੀਜੇ ਵਜੋਂ ਹੋ ਸਕਦਾ ਹੈ।"</string>
diff --git a/packages/PackageInstaller/res/values-pt-rBR/strings.xml b/packages/PackageInstaller/res/values-pt-rBR/strings.xml
index 098c4b0ce495..b9e5be871a7a 100644
--- a/packages/PackageInstaller/res/values-pt-rBR/strings.xml
+++ b/packages/PackageInstaller/res/values-pt-rBR/strings.xml
@@ -84,9 +84,9 @@
<string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"Para sua segurança, o tablet não tem permissão para instalar apps desconhecidos dessa fonte. Você pode mudar isso nas configurações."</string>
<string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"Para sua segurança, a TV não tem permissão para instalar apps desconhecidos dessa fonte. Você pode mudar isso nas configurações."</string>
<string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Para sua segurança, o smartphone não tem permissão para instalar apps desconhecidos dessa fonte. Você pode mudar isso nas configurações."</string>
- <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Seu smartphone e seus dados pessoais estão mais vulneráveis a ataques de apps desconhecidos. Ao instalar esse app, você concorda que é responsável por qualquer dano causado ao seu smartphone ou pela perda de dados que possa resultar do uso do app."</string>
- <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Seu tablet e seus dados pessoais estão mais vulneráveis a ataques de apps desconhecidos. Ao instalar esse app, você concorda que é responsável por qualquer dano causado ao seu tablet ou pela perda de dados que possa resultar do uso do app."</string>
- <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Sua TV e seus dados pessoais estão mais vulneráveis a ataques de apps desconhecidos. Ao instalar esse app, você concorda que é responsável por qualquer dano à sua TV ou pela perda de dados que possa resultar do uso do app."</string>
+ <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Seu smartphone e seus dados pessoais estão mais vulneráveis a ataques de apps desconhecidos. Ao instalar esse app, você concorda que é responsável por qualquer perda de dados ou dano ao dispositivo causados pelo uso desses apps."</string>
+ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Seu tablet e seus dados pessoais estão mais vulneráveis a ataques de apps desconhecidos. Ao instalar esse app, você concorda que é responsável por qualquer perda de dados ou dano ao dispositivo causados pelo uso desses apps."</string>
+ <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Sua TV e seus dados pessoais estão mais vulneráveis a ataques de apps desconhecidos. Ao instalar esse app, você concorda que é responsável por qualquer perda de dados ou dano ao dispositivo causados pelo uso desses apps."</string>
<string name="anonymous_source_continue" msgid="4375745439457209366">"Continuar"</string>
<string name="external_sources_settings" msgid="4046964413071713807">"Configurações"</string>
<string name="wear_app_channel" msgid="1960809674709107850">"Instalando/desinstalando apps do Wear"</string>
diff --git a/packages/PackageInstaller/res/values-pt-rPT/strings.xml b/packages/PackageInstaller/res/values-pt-rPT/strings.xml
index da4ffd0e3943..ae69ed12118b 100644
--- a/packages/PackageInstaller/res/values-pt-rPT/strings.xml
+++ b/packages/PackageInstaller/res/values-pt-rPT/strings.xml
@@ -24,7 +24,7 @@
<string name="installing" msgid="4921993079741206516">"A instalar…"</string>
<string name="installing_app" msgid="1165095864863849422">"A instalar <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>…"</string>
<string name="install_done" msgid="5987363587661783896">"App instalada."</string>
- <string name="install_confirm_question" msgid="7663733664476363311">"Pretende instalar esta app?"</string>
+ <string name="install_confirm_question" msgid="7663733664476363311">"Instalar esta app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Pretende atualizar esta app?"</string>
<string name="install_failed" msgid="5777824004474125469">"Aplicação não instalada."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Foi bloqueada a instalação do pacote."</string>
diff --git a/packages/PackageInstaller/res/values-pt/strings.xml b/packages/PackageInstaller/res/values-pt/strings.xml
index 098c4b0ce495..b9e5be871a7a 100644
--- a/packages/PackageInstaller/res/values-pt/strings.xml
+++ b/packages/PackageInstaller/res/values-pt/strings.xml
@@ -84,9 +84,9 @@
<string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"Para sua segurança, o tablet não tem permissão para instalar apps desconhecidos dessa fonte. Você pode mudar isso nas configurações."</string>
<string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"Para sua segurança, a TV não tem permissão para instalar apps desconhecidos dessa fonte. Você pode mudar isso nas configurações."</string>
<string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Para sua segurança, o smartphone não tem permissão para instalar apps desconhecidos dessa fonte. Você pode mudar isso nas configurações."</string>
- <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Seu smartphone e seus dados pessoais estão mais vulneráveis a ataques de apps desconhecidos. Ao instalar esse app, você concorda que é responsável por qualquer dano causado ao seu smartphone ou pela perda de dados que possa resultar do uso do app."</string>
- <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Seu tablet e seus dados pessoais estão mais vulneráveis a ataques de apps desconhecidos. Ao instalar esse app, você concorda que é responsável por qualquer dano causado ao seu tablet ou pela perda de dados que possa resultar do uso do app."</string>
- <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Sua TV e seus dados pessoais estão mais vulneráveis a ataques de apps desconhecidos. Ao instalar esse app, você concorda que é responsável por qualquer dano à sua TV ou pela perda de dados que possa resultar do uso do app."</string>
+ <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Seu smartphone e seus dados pessoais estão mais vulneráveis a ataques de apps desconhecidos. Ao instalar esse app, você concorda que é responsável por qualquer perda de dados ou dano ao dispositivo causados pelo uso desses apps."</string>
+ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Seu tablet e seus dados pessoais estão mais vulneráveis a ataques de apps desconhecidos. Ao instalar esse app, você concorda que é responsável por qualquer perda de dados ou dano ao dispositivo causados pelo uso desses apps."</string>
+ <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Sua TV e seus dados pessoais estão mais vulneráveis a ataques de apps desconhecidos. Ao instalar esse app, você concorda que é responsável por qualquer perda de dados ou dano ao dispositivo causados pelo uso desses apps."</string>
<string name="anonymous_source_continue" msgid="4375745439457209366">"Continuar"</string>
<string name="external_sources_settings" msgid="4046964413071713807">"Configurações"</string>
<string name="wear_app_channel" msgid="1960809674709107850">"Instalando/desinstalando apps do Wear"</string>
diff --git a/packages/PackageInstaller/res/values-sk/strings.xml b/packages/PackageInstaller/res/values-sk/strings.xml
index 88ade4394a9e..c2b23d646dae 100644
--- a/packages/PackageInstaller/res/values-sk/strings.xml
+++ b/packages/PackageInstaller/res/values-sk/strings.xml
@@ -83,7 +83,7 @@
<string name="app_name_unknown" msgid="6881210203354323926">"Neznáma"</string>
<string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"Váš tablet momentálne nemôže z bezpečnostných dôvodov inštalovať neznáme aplikácie z tohto zdroja. Môžete to zmeniť v Nastaveniach."</string>
<string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"Váš televízor momentálne nemôže z bezpečnostných dôvodov inštalovať neznáme aplikácie z tohto zdroja. Môžete to zmeniť v Nastaveniach."</string>
- <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Váš telefón momentálne nemôže z bezpečnostných dôvodov inštalovať neznáme aplikácie z tohto zdroja. Môžete to zmeniť v Nastaveniach."</string>
+ <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Váš telefón momentálne nemôže z bezpečnostných dôvodov inštalovať neznáme aplikácie z tohto zdroja. Môžete to zmeniť v nastaveniach."</string>
<string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Váš telefón a osobné údaje sú náchylnejšie na útok z neznámych aplikácií. Inštaláciou tejto aplikácie vyjadrujete súhlas s tým, že nesiete zodpovednosť za akékoľvek poškodenie telefónu alebo stratu údajov, ktoré by mohli nastať pri jej používaní."</string>
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Váš tablet a osobné dáta sú náchylnejšie na útok z neznámych aplikácií. Inštaláciou tejto aplikácie vyjadrujete súhlas s tým, že nesiete zodpovednosť za akékoľvek poškodenie tabletu alebo stratu dát, ktoré by mohli nastať pri jej používaní."</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Váš televízor a osobné údaje sú náchylnejšie na útok z neznámych aplikácií. Inštaláciou tejto aplikácie vyjadrujete súhlas s tým, že nesiete zodpovednosť za akékoľvek poškodenie televízora alebo stratu údajov, ktoré by mohli nastať pri jej používaní."</string>
diff --git a/packages/PackageInstaller/res/values-th/strings.xml b/packages/PackageInstaller/res/values-th/strings.xml
index 409672b31484..1014152a0ff5 100644
--- a/packages/PackageInstaller/res/values-th/strings.xml
+++ b/packages/PackageInstaller/res/values-th/strings.xml
@@ -83,7 +83,7 @@
<string name="app_name_unknown" msgid="6881210203354323926">"ไม่ทราบ"</string>
<string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"เพื่อความปลอดภัย ปัจจุบันไม่อนุญาตให้ติดตั้งแอปที่ไม่รู้จักจากแหล่งที่มานี้ในแท็บเล็ต คุณเปลี่ยนแปลงได้ในการตั้งค่า"</string>
<string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"เพื่อความปลอดภัย ปัจจุบันไม่อนุญาตให้ติดตั้งแอปที่ไม่รู้จักจากแหล่งที่มานี้ในทีวี คุณเปลี่ยนแปลงได้ในการตั้งค่า"</string>
- <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"เพื่อความปลอดภัย ปัจจุบันไม่อนุญาตให้ติดตั้งแอปที่ไม่รู้จักจากแหล่งที่มานี้ในโทรศัพท์ คุณเปลี่ยนแปลงได้ในการตั้งค่า"</string>
+ <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"เพื่อความปลอดภัย ปัจจุบันไม่อนุญาตให้ติดตั้งแอปที่ไม่รู้จักจากแหล่งที่มานี้ในโทรศัพท์ ซึ่งคุณเปลี่ยนเป็นอนุญาตได้ในการตั้งค่า"</string>
<string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"โทรศัพท์และข้อมูลส่วนตัวของคุณมีความเสี่ยงมากขึ้นที่จะถูกโจมตีจากแอปที่ไม่รู้จัก การติดตั้งแอปนี้แสดงว่าคุณยอมรับว่าจะรับผิดชอบต่อความเสียหายใดๆ ที่จะเกิดขึ้นกับโทรศัพท์หรือการสูญเสียข้อมูลที่อาจเกิดจากการใช้งานแอปดังกล่าว"</string>
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"แท็บเล็ตและข้อมูลส่วนตัวของคุณมีความเสี่ยงมากขึ้นที่จะถูกโจมตีจากแอปที่ไม่รู้จัก การติดตั้งแอปนี้แสดงว่าคุณยอมรับว่าจะรับผิดชอบต่อความเสียหายใดๆ ที่จะเกิดขึ้นกับแท็บเล็ตหรือการสูญเสียข้อมูลที่อาจเกิดจากการใช้งานแอปดังกล่าว"</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"ทีวีและข้อมูลส่วนตัวของคุณมีความเสี่ยงมากขึ้นที่จะถูกโจมตีจากแอปที่ไม่รู้จัก การติดตั้งแอปนี้แสดงว่าคุณยอมรับว่าจะรับผิดชอบต่อความเสียหายใดๆ ที่จะเกิดขึ้นกับทีวีหรือการสูญเสียข้อมูลที่อาจเกิดจากการใช้งานแอปดังกล่าว"</string>
diff --git a/packages/PackageInstaller/res/values-uk/strings.xml b/packages/PackageInstaller/res/values-uk/strings.xml
index 2169b17666b9..67b3e0b78d19 100644
--- a/packages/PackageInstaller/res/values-uk/strings.xml
+++ b/packages/PackageInstaller/res/values-uk/strings.xml
@@ -20,7 +20,7 @@
<string name="install" msgid="711829760615509273">"Установити"</string>
<string name="update" msgid="3932142540719227615">"Оновити"</string>
<string name="done" msgid="6632441120016885253">"Готово"</string>
- <string name="cancel" msgid="1018267193425558088">"Скасув."</string>
+ <string name="cancel" msgid="1018267193425558088">"Скасувати"</string>
<string name="installing" msgid="4921993079741206516">"Встановлення…"</string>
<string name="installing_app" msgid="1165095864863849422">"Установлюється <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>…"</string>
<string name="install_done" msgid="5987363587661783896">"Програму встановлено."</string>
diff --git a/packages/PackageInstaller/res/values-uz/strings.xml b/packages/PackageInstaller/res/values-uz/strings.xml
index f3d16b57a0cf..275ac47285e9 100644
--- a/packages/PackageInstaller/res/values-uz/strings.xml
+++ b/packages/PackageInstaller/res/values-uz/strings.xml
@@ -83,7 +83,7 @@
<string name="app_name_unknown" msgid="6881210203354323926">"Noaniq"</string>
<string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"Xavfsizlik yuzasidan, planshetingizga hozirda bu manbadan notanish ilovalarni o‘rnatishga ruxsat berilmagan. Buni sozlamalardan oʻzgartirish mumkin."</string>
<string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"Xavfsizlik yuzasidan, televizoringizga hozirda bu manbadan notanish ilovalarni o‘rnatishga ruxsat berilmagan. Buni sozlamalardan oʻzgartirish mumkin."</string>
- <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Xavfsizlik yuzasidan, telefoningizga hozirda bu manbadan notanish ilovalarni o‘rnatishga ruxsat berilmagan. Buni sozlamalardan oʻzgartirish mumkin."</string>
+ <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Xavfsizlik yuzasidan, telefoningizga hozir ushbu manbadan notanish ilovalarni o‘rnatishga ruxsat berilmagan. Buni Sozlamalarda oʻzgartirishingiz mumkin."</string>
<string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Telefoningiz va shaxsiy axborotlaringiz notanish ilovalar hujumiga zaif bo‘ladi. Bu ilovani o‘rnatish bilan telefoningizga yetkaziladigan shikast va axborotlaringizni o‘chirib yuborilishiga javobgarlikni o‘z zimmangizga olasiz."</string>
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Planshetingiz va shaxsiy axborotlaringiz notanish ilovalar hujumiga zaif bo‘ladi. Bu ilovani o‘rnatish bilan planshetingizga yetkaziladigan shikast va axborotlaringizni o‘chirib yuborilishiga javobgarlikni o‘z zimmangizga olasiz."</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"TV va shaxsiy axborotlaringiz notanish ilovalar hujumiga zaif bo‘ladi. Bu ilovani o‘rnatish bilan televizoringizga yetkaziladigan shikast va axborotlaringizni o‘chirib yuborilishiga javobgarlikni o‘z zimmangizga olasiz."</string>
diff --git a/packages/PackageInstaller/res/values-zh-rCN/strings.xml b/packages/PackageInstaller/res/values-zh-rCN/strings.xml
index 924397f6bef4..cbebb21aad76 100644
--- a/packages/PackageInstaller/res/values-zh-rCN/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rCN/strings.xml
@@ -83,7 +83,7 @@
<string name="app_name_unknown" msgid="6881210203354323926">"未知"</string>
<string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"出于安全考虑,目前已禁止您的平板电脑安装来自此来源的未知应用。您可以在“设置”中对此进行更改。"</string>
<string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"出于安全考虑,目前已禁止您的电视安装来自此来源的未知应用。您可以在“设置”中对此进行更改。"</string>
- <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"出于安全考虑,目前已禁止您的手机安装来自此来源的未知应用。您可以在“设置”中对此进行更改。"</string>
+ <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"出于安全考虑,您的手机目前不允许安装来自此来源的未知应用。您可以在“设置”中对此进行更改。"</string>
<string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"来历不明的应用很可能会损害您的手机和个人数据。安装该应用即表示,您同意对于因使用该应用可能导致的任何手机损坏或数据丢失情况,您负有全部责任。"</string>
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"来历不明的应用很可能会损害您的平板电脑和个人数据。安装该应用即表示,您同意对于因使用该应用可能导致的任何平板电脑损坏或数据丢失情况,您负有全部责任。"</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"来历不明的应用很可能会损害您的电视和个人数据。安装该应用即表示,您同意对于因使用该应用可能导致的任何电视损坏或数据丢失情况,您负有全部责任。"</string>
diff --git a/packages/PackageInstaller/res/values-zh-rTW/strings.xml b/packages/PackageInstaller/res/values-zh-rTW/strings.xml
index 383802ebc534..67c684b618e6 100644
--- a/packages/PackageInstaller/res/values-zh-rTW/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rTW/strings.xml
@@ -83,7 +83,7 @@
<string name="app_name_unknown" msgid="6881210203354323926">"不明"</string>
<string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"為了安全起見,你的平板電腦目前禁止安裝這個來源提供的不明應用程式。如要進行變更,請前往「設定」。"</string>
<string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"為了安全起見,你的電視目前禁止安裝這個來源提供的不明應用程式。如要進行變更,請前往「設定」。"</string>
- <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"為了安全起見,你的手機目前禁止安裝這個來源提供的不明應用程式。如要進行變更,請前往「設定」。"</string>
+ <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"為了安全起見,你的手機目前無法安裝此來源提供的不明應用程式。如要進行變更,請前往「設定」。"</string>
<string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"來歷不明的應用程式可能會損害你的手機和個人資料。如因安裝及使用這個應用程式,導致你的手機受損或資料遺失,請自行負責。"</string>
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"來歷不明的應用程式可能會損害你的平板電腦和個人資料。如因安裝及使用這個應用程式,導致你的平板電腦受損或資料遺失,請自行負責。"</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"來歷不明的應用程式可能會損害你的電視和個人資料。如因安裝及使用這個應用程式,導致你的電視受損或資料遺失,請自行負責。"</string>
diff --git a/packages/PrintSpooler/res/values-mr/strings.xml b/packages/PrintSpooler/res/values-mr/strings.xml
index e1fa3902cdf0..255fbbce96ba 100644
--- a/packages/PrintSpooler/res/values-mr/strings.xml
+++ b/packages/PrintSpooler/res/values-mr/strings.xml
@@ -82,7 +82,7 @@
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> प्रिंट करत आहे"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द करत आहे"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर एरर <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
- <string name="blocked_notification_title_template" msgid="1175435827331588646">"प्रिंटरने <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> अवरोधित केले"</string>
+ <string name="blocked_notification_title_template" msgid="1175435827331588646">"प्रिंटरने <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ब्लॉक केला"</string>
<string name="cancel" msgid="4373674107267141885">"रद्द करा"</string>
<string name="restart" msgid="2472034227037808749">"रीस्टार्ट करा"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"प्रिंटरवर कोणतेही कनेक्‍शन नाही"</string>
diff --git a/packages/SettingsLib/AppPreference/res/layout/preference_app.xml b/packages/SettingsLib/AppPreference/res/layout/preference_app.xml
index e65f7de2466a..12db901bdb69 100644
--- a/packages/SettingsLib/AppPreference/res/layout/preference_app.xml
+++ b/packages/SettingsLib/AppPreference/res/layout/preference_app.xml
@@ -55,6 +55,7 @@
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:maxLines="2"
+ android:hyphenationFrequency="normalFast"
android:textAppearance="?android:attr/textAppearanceListItem"/>
<TextView
@@ -62,6 +63,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textDirection="locale"
+ android:hyphenationFrequency="normalFast"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"/>
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarDelegate.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarDelegate.java
index 30e39731d41b..31e8cc709749 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarDelegate.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarDelegate.java
@@ -16,6 +16,8 @@
package com.android.settingslib.collapsingtoolbar;
+import static android.text.Layout.HYPHENATION_FREQUENCY_NORMAL_FAST;
+
import android.app.ActionBar;
import android.os.Build;
import android.view.LayoutInflater;
@@ -82,6 +84,9 @@ public class CollapsingToolbarDelegate {
mAppBarLayout = view.findViewById(R.id.app_bar);
if (mCollapsingToolbarLayout != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mCollapsingToolbarLayout.setLineSpacingMultiplier(TOOLBAR_LINE_SPACING_MULTIPLIER);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ mCollapsingToolbarLayout.setHyphenationFrequency(HYPHENATION_FREQUENCY_NORMAL_FAST);
+ }
}
disableCollapsingToolbarLayoutScrollingBehavior();
mToolbar = view.findViewById(R.id.action_bar);
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayout.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayout.java
index dbb4b5017e6b..1ead2f337314 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayout.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayout.java
@@ -16,6 +16,8 @@
package com.android.settingslib.collapsingtoolbar.widget;
+import static android.text.Layout.HYPHENATION_FREQUENCY_NORMAL_FAST;
+
import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
@@ -106,6 +108,9 @@ public class CollapsingCoordinatorLayout extends CoordinatorLayout {
mAppBarLayout = findViewById(R.id.app_bar);
if (mCollapsingToolbarLayout != null) {
mCollapsingToolbarLayout.setLineSpacingMultiplier(TOOLBAR_LINE_SPACING_MULTIPLIER);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ mCollapsingToolbarLayout.setHyphenationFrequency(HYPHENATION_FREQUENCY_NORMAL_FAST);
+ }
if (!TextUtils.isEmpty(mToolbarTitle)) {
mCollapsingToolbarLayout.setTitle(mToolbarTitle);
}
diff --git a/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml b/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
index 42700b3ace07..2c1fdd493c8a 100644
--- a/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
+++ b/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
@@ -53,6 +53,7 @@
android:paddingTop="16dp"
android:paddingBottom="8dp"
android:textColor="?android:attr/textColorSecondary"
+ android:hyphenationFrequency="normalFast"
android:ellipsize="marquee" />
<com.android.settingslib.widget.LinkTextView
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
index 383bf8eaf2e7..86fec50d7c21 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
@@ -30,7 +30,6 @@ import android.widget.Switch;
import android.widget.TextView;
import androidx.annotation.ColorInt;
-import androidx.annotation.Nullable;
import com.android.settingslib.utils.BuildCompatUtils;
@@ -123,14 +122,9 @@ public class MainSwitchBar extends LinearLayout implements CompoundButton.OnChec
}
@Override
- public void setOnClickListener(@Nullable OnClickListener l) {
- super.setOnClickListener(l);
- mSwitch.setOnClickListener(l);
- }
-
- @Override
public boolean performClick() {
- return mSwitch.performClick();
+ mSwitch.performClick();
+ return super.performClick();
}
/**
diff --git a/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml
index 906ff2cc09d5..64d100a43e68 100644
--- a/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml
+++ b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml
@@ -66,6 +66,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
+ android:hyphenationFrequency="normalFast"
android:textAppearance="?android:attr/textAppearanceListItem"/>
<LinearLayout
@@ -80,6 +81,7 @@
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textAlignment="viewStart"
+ android:hyphenationFrequency="normalFast"
android:textColor="?android:attr/textColorSecondary"/>
<TextView
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_selector_with_widget.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_selector_with_widget.xml
index 8bb56ff0a07d..2a550ef4e457 100644
--- a/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_selector_with_widget.xml
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_selector_with_widget.xml
@@ -66,6 +66,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
+ android:hyphenationFrequency="normalFast"
android:textAppearance="?android:attr/textAppearanceListItem"/>
<LinearLayout
@@ -80,6 +81,7 @@
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textAlignment="viewStart"
+ android:hyphenationFrequency="normalFast"
android:textColor="?android:attr/textColorSecondary"/>
<TextView
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v31/settingslib_preference.xml b/packages/SettingsLib/SettingsTheme/res/layout-v31/settingslib_preference.xml
index 23aa993cc8cc..d4d466a99301 100644
--- a/packages/SettingsLib/SettingsTheme/res/layout-v31/settingslib_preference.xml
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v31/settingslib_preference.xml
@@ -43,6 +43,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
+ android:hyphenationFrequency="normalFast"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee"/>
@@ -57,6 +58,7 @@
android:textAlignment="viewStart"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="10"
+ android:hyphenationFrequency="normalFast"
style="@style/PreferenceSummaryTextStyle"/>
</RelativeLayout>
diff --git a/packages/SettingsLib/TopIntroPreference/res/layout/top_intro_preference.xml b/packages/SettingsLib/TopIntroPreference/res/layout/top_intro_preference.xml
index 4d6e1b7f0ac8..b2a9037e3b79 100644
--- a/packages/SettingsLib/TopIntroPreference/res/layout/top_intro_preference.xml
+++ b/packages/SettingsLib/TopIntroPreference/res/layout/top_intro_preference.xml
@@ -33,5 +33,6 @@
android:clickable="false"
android:longClickable="false"
android:maxLines="10"
+ android:hyphenationFrequency="normalFast"
android:textAppearance="@style/TextAppearance.TopIntroText"/>
</LinearLayout> \ No newline at end of file
diff --git a/packages/SettingsLib/TwoTargetPreference/res/layout-v31/preference_two_target.xml b/packages/SettingsLib/TwoTargetPreference/res/layout-v31/preference_two_target.xml
index 2c35772de2ca..ac5807dc08de 100644
--- a/packages/SettingsLib/TwoTargetPreference/res/layout-v31/preference_two_target.xml
+++ b/packages/SettingsLib/TwoTargetPreference/res/layout-v31/preference_two_target.xml
@@ -41,6 +41,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
+ android:hyphenationFrequency="normalFast"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee"/>
@@ -52,6 +53,7 @@
android:layout_alignStart="@android:id/title"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
+ android:hyphenationFrequency="normalFast"
android:maxLines="10"/>
</RelativeLayout>
diff --git a/packages/SettingsLib/res/layout/preference_access_point.xml b/packages/SettingsLib/res/layout/preference_access_point.xml
index 802d604a44f9..4ad9d8040aaa 100644
--- a/packages/SettingsLib/res/layout/preference_access_point.xml
+++ b/packages/SettingsLib/res/layout/preference_access_point.xml
@@ -65,6 +65,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
+ android:hyphenationFrequency="normalFast"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee" />
@@ -76,6 +77,7 @@
android:layout_alignStart="@android:id/title"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
+ android:hyphenationFrequency="normalFast"
android:maxLines="10" />
</RelativeLayout>
diff --git a/packages/SettingsLib/res/layout/preference_checkable_two_target.xml b/packages/SettingsLib/res/layout/preference_checkable_two_target.xml
index f512f9b27131..cbe49cd5dba7 100644
--- a/packages/SettingsLib/res/layout/preference_checkable_two_target.xml
+++ b/packages/SettingsLib/res/layout/preference_checkable_two_target.xml
@@ -62,6 +62,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
+ android:hyphenationFrequency="normalFast"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee" />
@@ -73,6 +74,7 @@
android:layout_alignStart="@android:id/title"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
+ android:hyphenationFrequency="normalFast"
android:maxLines="10" />
</RelativeLayout>
diff --git a/packages/SettingsLib/res/layout/restricted_switch_preference.xml b/packages/SettingsLib/res/layout/restricted_switch_preference.xml
index 169ae97c1a6d..edea1444e83a 100644
--- a/packages/SettingsLib/res/layout/restricted_switch_preference.xml
+++ b/packages/SettingsLib/res/layout/restricted_switch_preference.xml
@@ -52,6 +52,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
+ android:hyphenationFrequency="normalFast"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee" />
@@ -62,6 +63,7 @@
android:layout_alignStart="@android:id/title"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
+ android:hyphenationFrequency="normalFast"
android:maxLines="10" />
<TextView android:id="@+id/additional_summary"
@@ -72,6 +74,7 @@
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="10"
+ android:hyphenationFrequency="normalFast"
android:visibility="gone" />
</RelativeLayout>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 9820b3ec9521..0aa32459948d 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Laai tans vinnig"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Laai tans stadig"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Laai tans draadloos"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Laaidok"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Laai nie"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Gekoppel, laai nie"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Gelaai"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 7551c3e8df18..7f1e6f80b868 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ኃይል በፍጥነት በመሙላት ላይ"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ኃይል በዝግታ በመሙላት ላይ"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"በገመድ-አልባ ኃይል በመሙላት ላይ"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"የኃይል መሙያ መትከያ"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ባትሪ እየሞላ አይደለም"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"ተገናኝቷል፣ ኃይል በመሙላት ላይ አይደለም"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ባትሪ ሞልቷል"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index a1342cd3f011..3bda387aca89 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"جارٍ الشحن سريعًا"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"جارٍ الشحن ببطء"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"جارٍ الشحن لاسلكيًا"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"وحدة الإرساء للشحن"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"لا يتم الشحن"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"الجهاز متصل بالشاحن، ولا يتم الشحن."</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"مشحونة"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index ea0e7a65088a..a2d5c1415a00 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"দ্ৰুততাৰে চাৰ্জ হৈছে"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"লাহে লাহে চাৰ্জ হৈছে"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"বেতাঁৰৰ মাধ্যমেৰে চাৰ্জ হৈ আছে"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"চাৰ্জিং ড’ক"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"চ্চাৰ্জ কৰা নাই"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"সংযোগ হৈ আছে, চাৰ্জ হৈ থকা নাই"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"চাৰ্জ হ’ল"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 8a2a2f77bba5..33c3e6a7fce4 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Sürətlə doldurulur"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Asta doldurulur"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Simsiz şarj edilir"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Şarj Doku"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Doldurulmur"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Qoşulub, şarj edilmir"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Şarj edilib"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index a91e9f7fb51d..fb202d38f3c6 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo se puni"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Sporo se puni"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Bežično punjenje"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Stanica za punjenje"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ne puni se"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Povezano, ne puni se"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Napunjeno"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index eace050fbb76..12b8f1bfdb09 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Хуткая зарадка"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Павольная зарадка"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Бесправадная зарадка"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Зарадная док-станцыя"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не зараджаецца"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Падключана, не зараджаецца"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Зараджаны"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index e43bd01b9ba3..b8fe104b4eb5 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Зарежда се бързо"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Зарежда се бавно"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Зарежда се безжично"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Докинг станция за зарежд."</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не се зарежда"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Свързано, не се зарежда"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Заредена"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index c20106fca38e..abcd1f4333e1 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"দ্রুত চার্জ হচ্ছে"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ধীরে চার্জ হচ্ছে"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"কেবল ছাড়া চার্জ হচ্ছে"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"চার্জিং ডক"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"চার্জ হচ্ছে না"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"কানেক্ট করা থাকলেও চার্জ করা হচ্ছে না"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"চার্জ হয়েছে"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 9b1e0b16feff..d8e0958b23d9 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo punjenje"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Sporo punjenje"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Bežično punjenje"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Priključna stanica"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ne puni se"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Povezano, ne puni se"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Napunjeno"</string>
@@ -570,7 +571,7 @@
<string name="user_add_profile_item_title" msgid="3111051717414643029">"Ograničeni profil"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"Dodati novog korisnika?"</string>
<string name="user_add_user_message_long" msgid="1527434966294733380">"Ovaj uređaj možete dijeliti s drugima ako napravite dodatne korisnike. Svaki korisnik ima svoj prostor koji može prilagoditi pomoću aplikacija, pozadinske slike i slično. Korisnici također mogu prilagoditi postavke uređaja koje utiču na sve ostale korisnike, kao što je WiFi.\n\nKada dodate novog korisnika, ta osoba treba postaviti svoj prostor.\n\nSvaki korisnik može ažurirati aplikacije za sve ostale korisnike. Postavke i usluge pristupačnosti možda se neće prenijeti na novog korisnika."</string>
- <string name="user_add_user_message_short" msgid="3295959985795716166">"Kada dodate novog korisnika, ta osoba treba postaviti svoj prostor. \n\n Svaki korisnik može ažurirati aplikacije za sve ostale korisnike."</string>
+ <string name="user_add_user_message_short" msgid="3295959985795716166">"Kada dodate novog korisnika, ta osoba treba postaviti svoj prostor. \n\nSvaki korisnik može ažurirati aplikacije za sve ostale korisnike."</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"Postaviti korisnika sada?"</string>
<string name="user_setup_dialog_message" msgid="269931619868102841">"Provjerite može li osoba uzeti uređaj i postaviti svoj prostor"</string>
<string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"Postaviti profil sada?"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 92615007c17a..d8201de2ed90 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregant ràpidament"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Carregant lentament"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Carregant sense fil"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Base de càrrega"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"No s\'està carregant"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Connectat; no s\'està carregant"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Carregada"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index a51f2ee28b9a..0ad57cfdc82a 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Rychlé nabíjení"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Pomalé nabíjení"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Bezdrátové nabíjení"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Nabíjecí dok"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nenabíjí se"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Připojeno, nenabíjí se"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Nabito"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index f3991645993b..6c6dd97ce79f 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Oplader hurtigt"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Oplader langsomt"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Trådløs opladning"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Dockingstation"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Oplader ikke"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Tilsluttet, oplader ikke"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Opladet"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 941f8024b7f0..85e42f583b0e 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Schnelles Aufladen"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Langsames Aufladen"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Kabelloses Laden"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Wird am Dock geladen"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Wird nicht geladen"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Verbunden, wird nicht geladen"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Aufgeladen"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index c15ea1099d03..5241417fb9f1 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ταχεία φόρτιση"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Αργή φόρτιση"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Ασύρματη φόρτιση"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Βάση φόρτισης"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Δεν φορτίζει"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Συνδεδεμένη, δεν φορτίζει"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Φορτισμένη"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 8a79c6092f89..a7bbdb5110e8 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charging rapidly"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Charging slowly"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Charging wirelessly"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Charging dock"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Connected, not charging"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Charged"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 36a1f7704da4..0aa60e29c541 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charging rapidly"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Charging slowly"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Charging wirelessly"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Charging dock"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Connected, not charging"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Charged"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 8a79c6092f89..a7bbdb5110e8 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charging rapidly"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Charging slowly"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Charging wirelessly"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Charging dock"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Connected, not charging"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Charged"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 8a79c6092f89..a7bbdb5110e8 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charging rapidly"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Charging slowly"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Charging wirelessly"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Charging dock"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Connected, not charging"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Charged"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index efdfc4fcc832..f0aa3d6575b2 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‏‏‏‎‎‏‏‏‏‏‎‎‎‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‎‏‏‎‏‏‎‎‎‎‏‎‏‎Charging rapidly‎‏‎‎‏‎"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‎‎‎‏‎‎‏‎‎‎‎‎‎‎‎‎‏‏‎‎‏‎‏‏‏‏‎‎‏‎‏‏‏‎‎‏‏‎‏‎‎‎‏‏‎‎‏‎‏‏‎‎‎‎‏‏‏‏‎Charging slowly‎‏‎‎‏‎"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‏‏‏‎‎‎‏‎‎‎‎‎‎‏‏‎‎‏‏‏‎‏‎‎‎‏‎‎‏‎‏‏‏‏‎‏‏‏‎‎‏‎‏‎‏‎Charging wirelessly‎‏‎‎‏‎"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‎‎‏‎‏‎‏‎‎‏‎‏‏‎‏‏‏‏‎‏‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‎‏‎‏‏‎‎‏‎‎‎‏‏‎‏‎‎‏‎Charging Dock‎‏‎‎‏‎"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‏‎‎‎‎‏‎‎‎‏‎‎‎‏‎‏‎‏‎‎‏‎‏‏‎‎‎‎‏‏‎‎‏‎‎‎‎‎‏‎‏‎Not charging‎‏‎‎‏‎"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‏‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‏‎‎‎‎‎‎‏‏‎‏‎‏‏‎‎‎‎‎‎‎‎‏‎‏‎‏‎Connected, not charging‎‏‎‎‏‎"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎‏‎‏‏‏‎‏‏‏‏‏‏‎‎‎‏‎‏‎‏‏‏‎‎‎‏‏‎‎‎‏‏‎‏‎‏‎‎‏‏‏‎‎‎‎‎Charged‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 030b9d7a2360..4672e3ec9fee 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Cargando rápidamente"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Carga lenta"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Carga inalámbrica"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Base de carga"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"No se está cargando."</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Conectado; no se está cargando"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Cargada"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 71e0b0ef8dc5..24cb2eb89e18 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carga rápida"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Carga lenta"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Carga inalámbrica"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Base de carga"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"No se está cargando"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Conectado pero sin cargar"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Cargada"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index ad2601a9ea57..bc847e2b24fb 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Kiirlaadimine"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Aeglaselt laadimine"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Juhtmevaba laadimine"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Laadimisdokk"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ei lae"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Ühendatud, ei laeta"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Laetud"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index e72801386c55..6795662cac3d 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Bizkor kargatzen"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Mantso kargatzen"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Hari gabe kargatzen"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Oinarrian kargatzen"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ez da kargatzen ari"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Konektatuta dago, baina ez da kargatzen ari"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Kargatuta"</string>
@@ -668,7 +669,7 @@
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Eman pantaila pizteko baimena"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Eman pantaila pizteko baimena aplikazioei. Baimena emanez gero, aplikazioek edonoiz piztu ahal izango dute pantaila, zuk halako asmorik izan ez arren."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren audioa igortzeari utzi nahi diozu?"</string>
- <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> aplikazioaren audioa igortzen baduzu, edo audio-irteera aldatzen baduzu, une hartako igorpena eten egingo da"</string>
+ <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> aplikazioaren audioa igortzen edo audio-irteera aldatzen baduzu, une hartako igorpena etengo da"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Igorri <xliff:g id="SWITCHAPP">%1$s</xliff:g> aplikazioaren audioa"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Aldatu audio-irteera"</string>
<string name="back_navigation_animation" msgid="8105467568421689484">"Atzera egiteko keinuaren animazio-igarleak"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index d049b7f0a103..52ff02172338 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"درحال شارژ شدن سریع"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"درحال شارژ شدن آهسته"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"درحال شارژ بی‌سیم"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"پایه شارژ"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"شارژ نمی‌شود"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"متصل، شارژ نمی‌شود"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"شارژ کامل شد"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 0e697f5ae2e2..d383919a9d73 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Nopea lataus"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Hidas lataus"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Langaton lataus"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Latausteline"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ei laturissa"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Yhdistetty, ei ladata"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Ladattu"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 051347df7758..24ce0012917c 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Recharge rapide"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Recharge lente"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"En recharge sans fil"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Station de recharge"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"N\'est pas en charge"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Connecté, pas en charge"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Chargée"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 0b4303715165..637cc8a2cc00 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -185,7 +185,7 @@
<string name="launch_defaults_none" msgid="8049374306261262709">"Aucun paramètre par défaut défini"</string>
<string name="tts_settings" msgid="8130616705989351312">"Paramètres de la synthèse vocale"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"Sortie de la synthèse vocale"</string>
- <string name="tts_default_rate_title" msgid="3964187817364304022">"Cadence"</string>
+ <string name="tts_default_rate_title" msgid="3964187817364304022">"Débit"</string>
<string name="tts_default_rate_summary" msgid="3781937042151716987">"Vitesse à laquelle le texte est énoncé"</string>
<string name="tts_default_pitch_title" msgid="6988592215554485479">"Ton"</string>
<string name="tts_default_pitch_summary" msgid="9132719475281551884">"Affecte le ton utilisé pour la synthèse vocale"</string>
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charge rapide"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Charge lente"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"En charge sans fil"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Station de charge"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Pas en charge"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Connectée, pas en charge"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Chargée"</string>
@@ -671,7 +672,7 @@
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Si vous diffusez <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou que vous modifiez le résultat, votre annonce actuelle s\'arrêtera"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Diffuser <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
<string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Modifier le résultat"</string>
- <string name="back_navigation_animation" msgid="8105467568421689484">"Animations pour prévisualiser le geste de retour"</string>
+ <string name="back_navigation_animation" msgid="8105467568421689484">"Animations pour prévisualiser le retour en arrière"</string>
<string name="back_navigation_animation_summary" msgid="741292224121599456">"Activer les animations système pour la prévisualisation du geste de retour."</string>
<string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Ce paramètre active les animations système pour la prévisualisation du geste de retour. Pour cela, enableOnBackInvokedCallback doit être défini sur \"True\" dans le fichier manifeste de chaque appli."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index f0e7172e3c9e..211f8a58f9b3 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Cargando rapidamente"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Cargando lentamente"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Cargando sen fíos"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Base de carga"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Non se está cargando"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Conectado, sen cargar"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Cargada"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 374c7d8c4473..0344f4f0e55f 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ઝડપથી ચાર્જ થાય છે"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ધીમેથી ચાર્જ થાય છે"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"વાયરલેસથી ચાર્જિંગ"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"ડૉકથી ચાર્જ થઈ રહ્યું છે"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ચાર્જ થઈ રહ્યું નથી"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"કનેક્ટ કરેલું છે, પણ ચાર્જ થઈ રહ્યું નથી"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ચાર્જ થયું"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index d038c271cdb4..85220983f63f 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"तेज़ चार्ज हो रही है"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"धीरे चार्ज हो रही है"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"वायरलेस चार्जिंग"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"चार्जिंग डॉक"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज नहीं हो रही है"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"कनेक्ट किया गया, चार्ज नहीं हो रहा है"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"बैटरी चार्ज हो गई"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index ad6f75d3b010..73b7e1a9b32f 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo punjenje"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Sporo punjenje"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Bežično punjenje"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Stanica za punjenje"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ne puni se"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Povezano, ne puni se"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Napunjeno"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 1b906f8ebe14..fb8a7372936c 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Gyorstöltés"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Lassú töltés"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Vezeték nélküli töltés"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Töltődokk"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nem tölt"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Csatlakoztatva, nem töltődik"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Feltöltve"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 2b6ea25e8d34..7176ae500425 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -338,7 +338,7 @@
<string name="verify_apps_over_usb_title" msgid="6031809675604442636">"Ստուգել հավելվածները USB-ի նկատմամբ"</string>
<string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"Ստուգել հավելվածների անվտանգությունը ADB/ADT-ի միջոցով տեղադրված լինելու դեպքում։"</string>
<string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"Bluetooth սարքերը կցուցադրվեն առանց անունների (միայն MAC հասցեները)"</string>
- <string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"Կասեցնում է Bluetooth-ի ձայնի բացարձակ ուժգնության գործառույթը՝ հեռավոր սարքերի հետ ձայնի ուժգնությանը վերաբերող խնդիրներ ունենալու դեպքում (օրինակ՝ երբ ձայնի ուժգնությունն անընդունելի է կամ դրա կառավարումը հնարավոր չէ):"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"Կասեցնում է Bluetooth-ի ձայնի բացարձակ ուժգնության գործառույթը՝ հեռավոր սարքերի հետ ձայնի ուժգնությանը վերաբերող խնդիրներ ունենալու դեպքում (օրինակ, երբ ձայնի ուժգնությունն անընդունելի է կամ դրա կառավարումը հնարավոր չէ):"</string>
<string name="bluetooth_enable_gabeldorsche_summary" msgid="2054730331770712629">"Միացնել Bluetooth Gabeldorsche գործառույթի զտիչը"</string>
<string name="enhanced_connectivity_summary" msgid="1576414159820676330">"Միացնում է «Տվյալների լավացված փոխանակում» գործառույթը։"</string>
<string name="enable_terminal_title" msgid="3834790541986303654">"Տեղային տերմինալ"</string>
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Արագ լիցքավորում"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Դանդաղ լիցքավորում"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Անլար լիցքավորում"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Լիցքավորում դոկ-կայանի միջոցով"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Չի լիցքավորվում"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Միացված է, չի լիցքավորվում"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Լիցքավորված է"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index d4e642eea4f6..6e1bff8c16da 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mengisi daya cepat"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Mengisi daya lambat"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Mengisi daya nirkabel"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Mengisi Daya di Dok"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Tidak mengisi daya"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Terhubung, tidak mengisi daya"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Terisi"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index d9e5a3964e31..9c8933df6abe 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hröð hleðsla"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Hæg hleðsla"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Hleður þráðlaust"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Hleður í dokku"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ekki í hleðslu"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Tengt, ekki í hleðslu"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Fullhlaðin"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index fa84ed5cfe47..52ef9684ee77 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ricarica veloce"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Ricarica lenta"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"In carica, wireless"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"In carica nel dock"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Non in carica"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Dispositivo connesso, non in carica"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Carica"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 90be29d57647..d95590a66fbf 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"הסוללה נטענת מהר"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"הסוללה נטענת לאט"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"בטעינה אלחוטית"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"אביזר עגינה לטעינה"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"לא בטעינה"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"מחובר, לא בטעינה"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"הסוללה טעונה"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 54abcd47e568..5fa42a26d553 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"急速充電中"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"低速充電中"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ワイヤレス充電中"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"充電ホルダー"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"充電していません"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"接続済み、充電していません"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"充電が完了しました"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 27d3a99ec0c9..8ea09619e3b9 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"სწრაფად იტენება"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ნელა იტენება"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"უსადენოდ დატენა"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"დამტენი სამაგრი"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"არ იტენება"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"დაკავშირებულია, არ იტენება"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"დატენილია"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 344509546dd1..91aea7bd907f 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Жылдам зарядталуда"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Баяу зарядталуда"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Сымсыз зарядталуда"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Қондыру станциясы зарядталуда"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Зарядталу орындалып жатқан жоқ"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Жалғанған, зарядталып жатқан жоқ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Зарядталды"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 49f9ed38f37e..fcbe6e5edb31 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"កំពុងសាកថ្មយ៉ាងឆាប់រហ័ស"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"កំពុង​សាកថ្មយឺត"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"កំពុង​សាកថ្ម​ឥតខ្សែ"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"ឧបករណ៍ភ្ជាប់សាកថ្ម"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"មិនកំពុង​សាក​ថ្ម"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"បានភ្ជាប់ មិនកំពុង​សាកថ្ម"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"បាន​សាក​ថ្មពេញ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 8dab685dec57..4f3b1b11410e 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ವೇಗದ ಚಾರ್ಜಿಂಗ್"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ನಿಧಾನ ಗತಿಯ ಚಾರ್ಜಿಂಗ್"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ವೈರ್‌ಲೆಸ್ ಚಾರ್ಜಿಂಗ್"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"ಚಾರ್ಜಿಂಗ್ ಡಾಕ್"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ಚಾರ್ಜ್‌ ಆಗುತ್ತಿಲ್ಲ"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"ಕನೆಕ್ಟ್ ಆಗಿದೆ, ಚಾರ್ಜ್ ಆಗುತ್ತಿಲ್ಲ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ಚಾರ್ಜ್ ಆಗಿದೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index cb8b932807b7..2133724d8ad3 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"고속 충전 중"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"저속 충전 중"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"무선 충전 중"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"충전 도크"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"충전 안함"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"연결됨, 충전 중 아님"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"충전됨"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index e99d55674aa9..b10056f1dea0 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ыкчам кубатталууда"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Жай кубатталууда"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Зымсыз кубатталууда"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Кубаттоо док бекети"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Кубат алган жок"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Туташты, кубатталган жок"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Кубатталды"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 15579a733b46..74acbc81f606 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -175,7 +175,7 @@
<string name="data_usage_ota" msgid="7984667793701597001">"ການອັບເດດລະບົບ"</string>
<string name="tether_settings_title_usb" msgid="3728686573430917722">"ການປ່ອຍສັນຍານຜ່ານ USB"</string>
<string name="tether_settings_title_wifi" msgid="4803402057533895526">"ຮັອດສະປອດເຄື່ອນທີ່"</string>
- <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"ປ່ອຍສັນຍານຜ່ານ Bluetooth"</string>
+ <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"ການປ່ອຍສັນຍານດ້ວຍ Bluetooth"</string>
<string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"ການປ່ອຍສັນຍານ"</string>
<string name="tether_settings_title_all" msgid="8910259483383010470">"ການປ່ອຍສັນຍານ &amp; ຮັອດສະປອດເຄື່ອນທີ່"</string>
<string name="managed_user_title" msgid="449081789742645723">"ແອັບເຮັດວຽກທັງໝົດ"</string>
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ກຳລັງສາກໄຟດ່ວນ"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ກຳລັງສາກໄຟຊ້າໆ"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ກຳລັງສາກໄຟໄຮ້ສາຍ"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"ກຳລັງສາກໄຟຜ່ານດັອກ"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ບໍ່ໄດ້ສາກໄຟ"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"ເຊື່ອມຕໍ່ແລ້ວ, ບໍ່ໄດ້ສາກໄຟ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ສາກເຕັມແລ້ວ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 8a85a2135c66..13eb79255918 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Greitai įkraunama"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Lėtai įkraunama"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Kraunama be laidų"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Įkrovimo dokas"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nekraunama"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Prijungta, neįkraunama"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Įkrauta"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 1b7ccf995488..1a9a6c380434 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Notiek ātrā uzlāde"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Notiek lēnā uzlāde"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Bezvadu uzlāde"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Uzlādes doks"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nenotiek uzlāde"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Ierīce pievienota, uzlāde nenotiek"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Uzlādēts"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 6e2b7ca20e52..98fd0043c0d1 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Брзо полнење"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Бавно полнење"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Се полни безжично"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Се полни на док"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не се полни"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Поврзано, не се полни"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Полна"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 828fe45f62c4..5c4cbf36c9ec 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"അതിവേഗ ചാർജിംഗ്"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"പതുക്കെയുള്ള ചാർജിംഗ്"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"വയർലെസായി ചാർജുചെയ്യുന്നു"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"ചാർജിംഗ് ഡോക്ക്"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ചാർജ്ജുചെയ്യുന്നില്ല"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"കണക്റ്റ് ചെയ്‌തിരിക്കുന്നു, ചാർജ് ചെയ്യുന്നില്ല"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ചാർജായി"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index b25a57c2ca67..475178ef726b 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Хурдан цэнэглэж байна"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Удаан цэнэглэж байна"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Утасгүй цэнэглэж байна"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Цэнэглэх холбогч"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Цэнэглэхгүй байна"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Холбогдсон, цэнэглээгүй байна"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Цэнэглэсэн"</string>
diff --git a/packages/SettingsLib/res/values-mr/arrays.xml b/packages/SettingsLib/res/values-mr/arrays.xml
index 25113d246947..45bc5b8011e0 100644
--- a/packages/SettingsLib/res/values-mr/arrays.xml
+++ b/packages/SettingsLib/res/values-mr/arrays.xml
@@ -31,7 +31,7 @@
<item msgid="7852381437933824454">"डिस्कनेक्ट करत आहे..."</item>
<item msgid="5046795712175415059">"डिस्कनेक्ट केले"</item>
<item msgid="2473654476624070462">"अयशस्वी"</item>
- <item msgid="9146847076036105115">"अवरोधित"</item>
+ <item msgid="9146847076036105115">"ब्लॉक केले"</item>
<item msgid="4543924085816294893">"तात्पुरते खराब कनेक्शन टाळत आहे"</item>
</string-array>
<string-array name="wifi_status_with_ssid">
@@ -45,7 +45,7 @@
<item msgid="1175040558087735707">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> वरून डिस्कनेक्ट करत आहे…"</item>
<item msgid="699832486578171722">"डिस्कनेक्ट केले"</item>
<item msgid="522383512264986901">"अयशस्वी"</item>
- <item msgid="3602596701217484364">"अवरोधित"</item>
+ <item msgid="3602596701217484364">"ब्लॉक केले"</item>
<item msgid="1999413958589971747">"तात्पुरते खराब कनेक्शन टाळत आहे"</item>
</string-array>
<string-array name="hdcp_checking_titles">
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 12bbcee38b48..d18a1f9a580a 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"वेगाने चार्ज होत आहे"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"हळू चार्ज होत आहे"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"वायरलेसने चार्ज होत आहे"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"चार्जिंग डॉक"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज होत नाही"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"कनेक्ट केले, चार्ज होत नाही"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"चार्ज झाली"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 2b6f62d16cfe..efdf98983b20 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mengecas dgn cepat"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Mengecas perlahan"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Mengecas tanpa wayar"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Dok Pengecasan"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Tidak mengecas"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Bersambung, tidak mengecas"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Sudah dicas"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 5aab523529e4..c3dac352ad25 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -448,8 +448,7 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (အနီ-အစိမ်း)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (အပြာ-အဝါ)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"အရောင်ပြင်ဆင်မှု"</string>
- <!-- syntax error in translation for accessibility_display_daltonizer_preference_subtitle (1522101114585266455) org.xmlpull.v1.XmlPullParserException: expected: /string read: li (position:END_TAG </li>@1:326 in <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"အရောင် အမှန်ပြင်ခြင်းသည် အောက်ပါတို့အတွက် အသုံးဝင်နိုင်သည်-&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;အရောင်များကို ပိုမိုမှန်ကန်စွာ ကြည့်ရှုခြင်း&lt;/li&gt; &lt;li&gt;&amp;nbsp;အာရုံစိုက်နိုင်ရန် အရောင်များ ဖယ်ရှားခြင်း</li> </ol>"</string>
-) -->
+ <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"အရောင် အမှန်ပြင်ခြင်းသည် အောက်ပါတို့အတွက် အသုံးဝင်နိုင်သည်-&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;အရောင်များကို ပိုမိုမှန်ကန်စွာ ကြည့်ရှုခြင်း&amp;lt&lt;/li&gt; &lt;li&gt;&amp;nbsp;အာရုံစိုက်နိုင်ရန် အရောင်များ ဖယ်ရှားခြင်း&lt;/li&gt; &lt;/ol&gt;"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> မှ ကျော်၍ လုပ်ထားသည်။"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ခန့် ကျန်သည်"</string>
@@ -483,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"အမြန် အားသွင်းနေသည်"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"နှေးကွေးစွာ အားသွင်း"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ကြိုးမဲ့ အားသွင်းနေသည်"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"အားသွင်းအထိုင်"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"အားသွင်းမနေပါ"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"ချိတ်ဆက်ထားသည်၊ အားသွင်းမနေပါ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"အားသွင်းပြီးပါပြီ"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 8899644963d0..f6c82f8eaabd 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Lader raskt"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Lader sakte"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Lader trådløst"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Ladedokk"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Lader ikke"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Tilkoblet, lader ikke"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Ladet"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index d59ceebcc774..5fa4daa8fb9c 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"द्रुत गतिमा चार्ज गरिँदै छ"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ढिलो चार्ज हुँदै छ"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"वायरलेस तरिकाले चार्ज गरिँदै छ"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"डक चार्ज हुँदै छ"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज भइरहेको छैन"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"कनेक्ट गरिएको छ, चार्ज भइरहेको छैन"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"चार्ज भयो"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 8a487619ab82..360582fb932c 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Snel opladen"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Langzaam opladen"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Draadloos opladen"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Oplaaddock"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Wordt niet opgeladen"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Verbonden, wordt niet opgeladen"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Opgeladen"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 3ae906d47d0a..e25124c953b1 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ଶୀଘ୍ର ଚାର୍ଜ ହେଉଛି"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ଧୀରେ ଚାର୍ଜ ହେଉଛି"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ୱେୟରଲେସ ଭାବେ ଚାର୍ଜିଂ"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"ଡକ ଚାର୍ଜ ହେଉଛି"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ଚାର୍ଜ ହେଉନାହିଁ"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"ସଂଯୋଗ କରାଯାଇଛି, ଚାର୍ଜ ହେଉନାହିଁ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ଚାର୍ଜ ହୋଇଯାଇଛି"</string>
@@ -491,7 +492,7 @@
<string name="disabled" msgid="8017887509554714950">"ଅକ୍ଷମ ହୋଇଛି"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"ଅନୁମତି ଦିଆଯାଇଛି"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"ଅନୁମତି ନାହିଁ"</string>
- <string name="install_other_apps" msgid="3232595082023199454">"ଅଜଣା ଆପ୍‌ ଇନଷ୍ଟଲ୍‌ କରନ୍ତୁ"</string>
+ <string name="install_other_apps" msgid="3232595082023199454">"ଅଜଣା ଆପ ଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
<string name="home" msgid="973834627243661438">"ସେଟିଂସ ହୋମ"</string>
<string-array name="battery_labels">
<item msgid="7878690469765357158">"0%"</item>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 84b0f8bdfaf6..ca58fe946b76 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ਤੇਜ਼ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ਬਿਨਾਂ ਤਾਰ ਤੋਂ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"ਡੌਕ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਿਹਾ"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"ਕਨੈਕਟ ਹੈ, ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਹੀ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ਚਾਰਜ ਹੋ ਗਈ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 523ec7c878b8..860ee17f4a14 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Szybkie ładowanie"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Wolne ładowanie"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Ładowanie bezprzewodowe"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Ładowanie na stacji dokującej"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nie podłączony"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Podłączono, brak ładowania"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Naładowana"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index d7d723ceed44..4854709fb614 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -149,7 +149,7 @@
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Parear"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PAREAR"</string>
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Cancelar"</string>
- <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"O pareamento dá acesso a seus contatos e ao histórico de chamadas quando estiver conectado."</string>
+ <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"O pareamento dá acesso a seus contatos e ao histórico de ligações quando estiver conectado."</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g> por causa de um PIN ou senha incorretos."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"Não é possível se comunicar com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregando rápido"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Carregando devagar"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Carregando sem fio"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Base de carregamento"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Não está carregando"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Conectado sem carregar"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Carregada"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 1a8bd8993a94..2ebf1d71e133 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregamento rápido"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Carregamento lento"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"A carregar sem fios"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Est. ancor. carreg."</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Não está a carregar"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Ligado, não está a carregar"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Carregada"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index d7d723ceed44..4854709fb614 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -149,7 +149,7 @@
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Parear"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PAREAR"</string>
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Cancelar"</string>
- <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"O pareamento dá acesso a seus contatos e ao histórico de chamadas quando estiver conectado."</string>
+ <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"O pareamento dá acesso a seus contatos e ao histórico de ligações quando estiver conectado."</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g> por causa de um PIN ou senha incorretos."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"Não é possível se comunicar com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregando rápido"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Carregando devagar"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Carregando sem fio"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Base de carregamento"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Não está carregando"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Conectado sem carregar"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Carregada"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 9ef302c806a9..3dd56eb2b311 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Se încarcă rapid"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Se încarcă lent"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Se încarcă wireless"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Suport de încărcare"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nu se încarcă"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Conectat, nu se încarcă"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Încărcată"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index fd061549d752..68543a03811f 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Быстрая зарядка"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Медленная зарядка"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Беспроводная зарядка"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Док-станция: зарядка"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не заряжается"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Подключено, не заряжается"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Батарея заряжена"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 347c5c8f934d..dbc1fc2a89c4 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ශීඝ්‍ර ආරෝපණය"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"සෙමින් ආරෝපණය"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"නොරැහැන්ව ආරෝපණය වේ"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"ආරෝපණ ඩොකය"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ආරෝපණය නොවේ"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"සම්බන්ධයි, ආරෝපණය නොවේ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"අරෝපිතයි"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 7394985be2ff..a3a0e2307fb1 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -451,7 +451,7 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Úprava farieb môže byť užitočná, keď chcete:&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;zobrazovať farby presnejšie;&lt;/li&gt; &lt;li&gt;&amp;nbsp;odstrániť farby, aby ste sa mohli sústrediť.&lt;/li&gt; &lt;/ol&gt;"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Prekonané predvoľbou <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <string name="power_remaining_duration_only" msgid="8264199158671531431">"Zostáva približne <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ešte približne <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Zostáva približne <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Zostáva približne <xliff:g id="TIME_REMAINING">%1$s</xliff:g> – závisí to od intenzity využitia"</string>
<string name="power_discharging_duration_enhanced" msgid="1800465736237672323">"Zostáva približne <xliff:g id="TIME_REMAINING">%1$s</xliff:g> – závisí to od intenzity využitia (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Rýchle nabíjanie"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Pomalé nabíjanie"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Nabíja sa bezdrôtovo"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Nabíjací dok"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nenabíja sa"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Pripojené, nenabíja sa"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Nabité"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 28824a3504d3..7e2172fb65fe 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hitro polnjenje"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Počasno polnjenje"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Brezžično polnjenje"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Polnjenje na nosilcu"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Se ne polni"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Povezano, se ne polni"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Napolnjeno"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 27fe4549e8e3..146471d1fe95 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Karikim i shpejtë"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Po karikohet ngadalë"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Po karikohet pa tel"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Në stacion karikimi"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nuk po karikohet"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Lidhur, jo në karikim"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Karikuar"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 768cb1e6fde1..e429a635ce7f 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Брзо се пуни"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Споро се пуни"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Бежично пуњење"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Станица за пуњење"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не пуни се"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Повезано, не пуни се"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Напуњено"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 2be1898e447d..c92356ba794c 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Laddas snabbt"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Laddas långsamt"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Laddas trådlöst"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Dockningsstation"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Laddar inte"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Ansluten, laddas inte"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Laddat"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index b4bd3cb27e08..ee66c7346a52 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Inachaji kwa kasi"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Inachaji pole pole"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Inachaji bila kutumia waya"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Kituo cha Kuchaji"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Haichaji"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Imeunganishwa, haichaji"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Imechajiwa"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index c79a2ede9d7f..1c60acc19aff 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"வேகமாக சார்ஜாகிறது"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"மெதுவாக சார்ஜாகிறது"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"வயரின்றி சார்ஜாகிறது"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"சார்ஜிங் டாக்"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"சார்ஜ் செய்யப்படவில்லை"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"இணைக்கப்பட்டுள்ளது, சார்ஜாகவில்லை"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"சார்ஜாகிவிட்டது"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index d0855a4e1c1d..5963495534fc 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"వేగవంతమైన ఛార్జింగ్"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"నెమ్మదిగా ఛార్జింగ్"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"వైర్‌లెస్ ఛార్జింగ్"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"ఛార్జింగ్ డాక్"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ఛార్జ్ కావడం లేదు"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"కనెక్ట్ చేయబడింది, ఛార్జ్ చేయబడలేదు"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ఛార్జ్ చేయబడింది"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index fd4022be2495..e46bdc481a00 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"กำลังชาร์จอย่างเร็ว"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"กำลังชาร์จอย่างช้าๆ"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"กำลังชาร์จแบบไร้สาย"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"กำลังชาร์จบนแท่น"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ไม่ได้ชาร์จ"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"เชื่อมต่ออยู่ ไม่ได้ชาร์จ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ชาร์จแล้ว"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 137a43980989..21d07c1a314a 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mabilis na charge"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Mabagal na charge"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Wireless na nagcha-charge"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Charging Dock"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Hindi nagcha-charge"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Nakakonekta, hindi nagcha-charge"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Nasingil"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index f8b230498733..0a5f7da5a00d 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hızlı şarj oluyor"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Yavaş şarj oluyor"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Kablosuz şarj oluyor"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Şarj Yuvası"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Şarj olmuyor"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Bağlandı, şarj olmuyor"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Şarj oldu"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 9666bd6604f8..769aab78a995 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Швидке заряджання"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Повільне заряджання"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Бездротове заряджання"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Зарядка: док-станція"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не заряджається"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Підключено, не заряджається"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Заряджено"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index c8f396ea386a..5d7928bfe9e9 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"تیزی سے چارج ہو رہا ہے"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"آہستہ چارج ہو رہی ہے"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"وائرلیس طریقے سے چارج ہو رہی ہے"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"چارجنگ ڈاک"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"چارج نہیں ہو رہا ہے"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"منسلک ہے، چارج نہیں ہو رہی ہے"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"چارج ہو گئی"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 6c4763ef20ee..46cd59690f0b 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Tezkor quvvat olmoqda"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Sekin quvvat olmoqda"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Simsiz quvvat olmoqda"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Quvvatlash doki"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Quvvat olmayapti"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Ulangan, quvvat olmayapti"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Quvvat oldi"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 6be9b8a161c9..e11fefd2d923 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Đang sạc nhanh"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Đang sạc chậm"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Đang sạc không dây"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Đế sạc"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Hiện không sạc"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Đã kết nối nhưng chưa sạc"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Đã sạc"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 6f678f4036e0..1a44ac25bbad 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"正在快速充电"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"正在慢速充电"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"正在无线充电"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"充电基座"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"未在充电"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"已连接,未充电"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"已充满电"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 03d4559b1949..b94c6d16221c 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"快速充電中"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"慢速充電中"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"無線充電中"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"充電插座"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"非充電中"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"已連接,非充電中"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"已充滿電"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 16baf82435a8..bb126c27d10a 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"快速充電中"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"慢速充電中"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"正在進行無線充電"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"充電座架"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"非充電中"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"已連接,尚未充電"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"充電完成"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index e2fab129f354..c9d4b630a7e8 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -482,6 +482,7 @@
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ishaja ngokushesha"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Ishaja kancane"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Iyashaja ngaphandle kwentambo"</string>
+ <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Idokhu yokushaja"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ayishaji"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Ixhunyiwe, ayishaji"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Kushajiwe"</string>
diff --git a/packages/SystemUI/docs/device-entry/doze.md b/packages/SystemUI/docs/device-entry/doze.md
index 5ff8851b4c69..6b6dce5da169 100644
--- a/packages/SystemUI/docs/device-entry/doze.md
+++ b/packages/SystemUI/docs/device-entry/doze.md
@@ -17,6 +17,9 @@ Note: The default UI used in AOD shares views with the Lock Screen and does not
### DOZE
Device is asleep and listening for enabled pulsing and wake-up gesture triggers. In this state, no UI shows.
+### DOZE_SUSPEND_TRIGGERS
+Device is asleep and not listening for any triggers to wake up. This state is used only when CAR_MODE is active. In this state, no UI shows.
+
### DOZE_AOD
Device is asleep, showing UI, and listening for enabled pulsing and wake-up triggers. In this state, screen brightness is handled by [DozeScreenBrightness][5] which uses the brightness sensor specified by `doze_brightness_sensor_type` in the [SystemUI config][6]. To save power, this should be a low-powered sensor that shouldn't trigger as often as the light sensor used for on-screen adaptive brightness.
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
index 0c8202260907..beba0ee61dfe 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
@@ -21,8 +21,8 @@ import android.app.WallpaperColors
import android.graphics.Color
import com.android.internal.graphics.ColorUtils
import com.android.internal.graphics.cam.Cam
+import com.android.internal.graphics.cam.CamUtils
import kotlin.math.absoluteValue
-import kotlin.math.max
import kotlin.math.roundToInt
const val TAG = "ColorScheme"
@@ -43,13 +43,13 @@ internal interface Hue {
* second item in the pair is a hue rotation that should be applied
*/
fun getHueRotation(sourceHue: Float, hueAndRotations: List<Pair<Int, Int>>): Double {
- for (i in 0..hueAndRotations.size) {
- val previousIndex = if (i == 0) hueAndRotations.size - 1 else i - 1
- val thisHue = hueAndRotations[i].first
- val previousHue = hueAndRotations[previousIndex].first
- if (ColorScheme.angleIsBetween(sourceHue, thisHue, previousHue)) {
- return ColorScheme.wrapDegreesDouble(sourceHue.toDouble() +
- hueAndRotations[previousIndex].second)
+ val sanitizedSourceHue = (if (sourceHue < 0 || sourceHue >= 360) 0 else sourceHue).toFloat()
+ for (i in 0..hueAndRotations.size - 2) {
+ val thisHue = hueAndRotations[i].first.toFloat()
+ val nextHue = hueAndRotations[i + 1].first.toFloat()
+ if (thisHue <= sanitizedSourceHue && sanitizedSourceHue < nextHue) {
+ return ColorScheme.wrapDegreesDouble(sanitizedSourceHue.toDouble() +
+ hueAndRotations[i].second)
}
}
@@ -79,7 +79,7 @@ internal class HueSubtract(val amountDegrees: Double) : Hue {
internal class HueVibrantSecondary() : Hue {
val hueToRotations = listOf(Pair(0, 18), Pair(41, 15), Pair(61, 10), Pair(101, 12),
- Pair(131, 15), Pair(181, 18), Pair(251, 15), Pair(301, 12))
+ Pair(131, 15), Pair(181, 18), Pair(251, 15), Pair(301, 12), Pair(360, 12))
override fun get(sourceColor: Cam): Double {
return getHueRotation(sourceColor.hue, hueToRotations)
}
@@ -87,7 +87,7 @@ internal class HueVibrantSecondary() : Hue {
internal class HueVibrantTertiary() : Hue {
val hueToRotations = listOf(Pair(0, 35), Pair(41, 30), Pair(61, 20), Pair(101, 25),
- Pair(131, 30), Pair(181, 35), Pair(251, 30), Pair(301, 25))
+ Pair(131, 30), Pair(181, 35), Pair(251, 30), Pair(301, 25), Pair(360, 25))
override fun get(sourceColor: Cam): Double {
return getHueRotation(sourceColor.hue, hueToRotations)
}
@@ -95,7 +95,7 @@ internal class HueVibrantTertiary() : Hue {
internal class HueExpressiveSecondary() : Hue {
val hueToRotations = listOf(Pair(0, 45), Pair(21, 95), Pair(51, 45), Pair(121, 20),
- Pair(141, 45), Pair(191, 90), Pair(271, 45), Pair(321, 45))
+ Pair(151, 45), Pair(191, 90), Pair(271, 45), Pair(321, 45), Pair(360, 45))
override fun get(sourceColor: Cam): Double {
return getHueRotation(sourceColor.hue, hueToRotations)
}
@@ -103,7 +103,7 @@ internal class HueExpressiveSecondary() : Hue {
internal class HueExpressiveTertiary() : Hue {
val hueToRotations = listOf(Pair(0, 120), Pair(21, 120), Pair(51, 20), Pair(121, 45),
- Pair(141, 20), Pair(191, 15), Pair(271, 20), Pair(321, 120))
+ Pair(151, 20), Pair(191, 15), Pair(271, 20), Pair(321, 120), Pair(360, 120))
override fun get(sourceColor: Cam): Double {
return getHueRotation(sourceColor.hue, hueToRotations)
}
@@ -111,34 +111,13 @@ internal class HueExpressiveTertiary() : Hue {
internal interface Chroma {
fun get(sourceColor: Cam): Double
-
- /**
- * Given a hue, and a mapping of hues to hue rotations, find which hues in the mapping the
- * hue fall betweens, and use the hue rotation of the lower hue.
- *
- * @param sourceHue hue of source color
- * @param hueAndChromas list of pairs, where the first item in a pair is a hue, and the
- * second item in the pair is a chroma that should be applied
- */
- fun getSpecifiedChroma(sourceHue: Float, hueAndChromas: List<Pair<Int, Int>>): Double {
- for (i in 0..hueAndChromas.size) {
- val previousIndex = if (i == 0) hueAndChromas.size - 1 else i - 1
- val thisHue = hueAndChromas[i].first
- val previousHue = hueAndChromas[previousIndex].first
- if (ColorScheme.angleIsBetween(sourceHue, thisHue, previousHue)) {
- return hueAndChromas[i].second.toDouble()
- }
- }
-
- // If this statement executes, something is wrong, there should have been a rotation
- // found using the arrays.
- return sourceHue.toDouble()
- }
}
-internal class ChromaMinimum(val chroma: Double) : Chroma {
+internal class ChromaMaxOut : Chroma {
override fun get(sourceColor: Cam): Double {
- return max(sourceColor.chroma.toDouble(), chroma)
+ // Intentionally high. Gamut mapping from impossible HCT to sRGB will ensure that
+ // the maximum chroma is reached, even if lower than this constant.
+ return 130.0
}
}
@@ -192,11 +171,11 @@ enum class Style(internal val coreSpec: CoreSpec) {
n2 = TonalSpec(HueSource(), ChromaConstant(8.0))
)),
VIBRANT(CoreSpec(
- a1 = TonalSpec(HueSource(), ChromaMinimum(48.0)),
+ a1 = TonalSpec(HueSource(), ChromaMaxOut()),
a2 = TonalSpec(HueVibrantSecondary(), ChromaConstant(24.0)),
a3 = TonalSpec(HueVibrantTertiary(), ChromaConstant(32.0)),
- n1 = TonalSpec(HueSource(), ChromaConstant(12.0)),
- n2 = TonalSpec(HueSource(), ChromaConstant(14.0))
+ n1 = TonalSpec(HueSource(), ChromaConstant(8.0)),
+ n2 = TonalSpec(HueSource(), ChromaConstant(12.0))
)),
EXPRESSIVE(CoreSpec(
a1 = TonalSpec(HueAdd(240.0), ChromaConstant(40.0)),
@@ -229,7 +208,7 @@ enum class Style(internal val coreSpec: CoreSpec) {
}
class ColorScheme(
- @ColorInt seed: Int,
+ @ColorInt val seed: Int,
val darkTheme: Boolean,
val style: Style = Style.TONAL_SPOT
) {
@@ -293,12 +272,14 @@ class ColorScheme(
override fun toString(): String {
return "ColorScheme {\n" +
- " neutral1: ${humanReadable(neutral1)}\n" +
- " neutral2: ${humanReadable(neutral2)}\n" +
- " accent1: ${humanReadable(accent1)}\n" +
- " accent2: ${humanReadable(accent2)}\n" +
- " accent3: ${humanReadable(accent3)}\n" +
+ " seed color: ${stringForColor(seed)}\n" +
" style: $style\n" +
+ " palettes: \n" +
+ " ${humanReadable("PRIMARY", accent1)}\n" +
+ " ${humanReadable("SECONDARY", accent2)}\n" +
+ " ${humanReadable("TERTIARY", accent3)}\n" +
+ " ${humanReadable("NEUTRAL", neutral1)}\n" +
+ " ${humanReadable("NEUTRAL VARIANT", neutral2)}\n" +
"}"
}
@@ -416,13 +397,6 @@ class ColorScheme(
return seeds
}
- internal fun angleIsBetween(angle: Float, a: Int, b: Int): Boolean {
- if (a < b) {
- return a <= angle && angle <= b
- }
- return a <= angle || angle <= b
- }
-
private fun wrapDegrees(degrees: Int): Int {
return when {
degrees < 0 -> {
@@ -455,8 +429,20 @@ class ColorScheme(
return 180f - ((a - b).absoluteValue - 180f).absoluteValue
}
- private fun humanReadable(colors: List<Int>): String {
- return colors.joinToString { "#" + Integer.toHexString(it) }
+ private fun stringForColor(color: Int): String {
+ val width = 4
+ val hct = Cam.fromInt(color)
+ val h = "H${hct.hue.roundToInt().toString().padEnd(width)}"
+ val c = "C${hct.chroma.roundToInt().toString().padEnd(width)}"
+ val t = "T${CamUtils.lstarFromInt(color).roundToInt().toString().padEnd(width)}"
+ val hex = Integer.toHexString(color).replaceRange(0, 2, "").uppercase()
+ return "$h$c$t = #$hex"
+ }
+
+ private fun humanReadable(paletteName: String, colors: List<Int>): String {
+ return "$paletteName\n" + colors.map {
+ stringForColor(it)
+ }.joinToString(separator = "\n") { it }
}
private fun score(cam: Cam, proportion: Double): Double {
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 64aa8ee84423..babe924c4615 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -164,21 +164,21 @@
Displayed in a dialog box. -->
<string name="kg_password_wrong_pin_code_pukked">Incorrect SIM PIN code you must now contact your carrier to unlock your device.</string>
<!-- Instructions telling the user that they entered the wrong SIM PIN while trying
- to unlock the keyguard. Displayed in a dialog box. -->
- <plurals name="kg_password_wrong_pin_code">
- <item quantity="one">Incorrect SIM PIN code, you have <xliff:g id="number">%d</xliff:g> remaining attempt before you must contact your carrier to unlock your device.</item>
- <item quantity="other">Incorrect SIM PIN code, you have <xliff:g id="number">%d</xliff:g> remaining attempts.</item>
- </plurals>
+ to unlock the keyguard. Displayed in a dialog box. [CHAR LIMIT=NONE] -->
+ <string name="kg_password_wrong_pin_code"> {count, plural,
+ =1 {Incorrect SIM PIN code, you have # remaining attempt before you must contact your carrier to unlock your device.}
+ other {Incorrect SIM PIN code, you have # remaining attempts. }
+ }</string>
<!-- Instructions telling the user that they have exhausted SIM PUK retries and the SIM is now unusable.
Displayed in a dialog box. -->
<string name="kg_password_wrong_puk_code_dead">SIM is unusable. Contact your carrier.</string>
<!-- Instructions telling the user that they entered the wrong puk while trying
- to unlock the keyguard. Displayed in a dialog box. -->
- <plurals name="kg_password_wrong_puk_code">
- <item quantity="one">Incorrect SIM PUK code, you have <xliff:g id="number">%d</xliff:g> remaining attempt before SIM becomes permanently unusable.</item>
- <item quantity="other">Incorrect SIM PUK code, you have <xliff:g id="number">%d</xliff:g> remaining attempts before SIM becomes permanently unusable.</item>
- </plurals>
+ to unlock the keyguard. Displayed in a dialog box. [CHAR LIMIT=NONE] -->
+ <string name="kg_password_wrong_puk_code">{count, plural,
+ =1 {Incorrect SIM PUK code, you have # remaining attempt before SIM becomes permanently unusable.}
+ other {Incorrect SIM PUK code, you have # remaining attempts before SIM becomes permanently unusable.}
+ }</string>
<!-- Instructions telling the user that the operation to unlock the keyguard
with SIM PIN failed. Displayed in one line in a large font. -->
<string name="kg_password_pin_failed">SIM PIN operation failed!</string>
@@ -220,24 +220,20 @@
<!-- Face hint message when finger was not recognized. [CHAR LIMIT=20] -->
<string name="kg_face_not_recognized">Not recognized</string>
- <!-- Error message indicating that the camera privacy sensor has been turned on [CHAR LIMIT=NONE] -->
- <string name="kg_face_sensor_privacy_enabled">To use Face Unlock, turn on <b>Camera access</b> in Settings > Privacy</string>
-
- <!-- Instructions telling the user remaining times when enter SIM PIN view. -->
- <plurals name="kg_password_default_pin_message">
- <item quantity="one">Enter SIM PIN. You have <xliff:g id="number">%d</xliff:g> remaining
-attempt before you must contact your carrier to unlock your device.</item>
- <item quantity="other">Enter SIM PIN. You have <xliff:g id="number">%d</xliff:g> remaining
-attempts.</item>
- </plurals>
-
- <!-- Instructions telling the user remaining times when enter SIM PUK view. -->
- <plurals name="kg_password_default_puk_message">
- <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="
-number">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact carrier for details.</item>
- <item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="
-number">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact carrier for details.</item>
- </plurals>
+ <!-- Error message indicating that the camera privacy sensor has been turned on [CHAR LIMIT=53] -->
+ <string name="kg_face_sensor_privacy_enabled">To use Face Unlock, turn on camera access in Settings</string>
+
+ <!-- Instructions telling the user remaining times when enter SIM PIN view. [CHAR LIMIT=NONE] -->
+ <string name="kg_password_default_pin_message">{count, plural,
+ =1 {Enter SIM PIN. You have # remaining attempt before you must contact your carrier to unlock your device.}
+ other {Enter SIM PIN. You have # remaining attempts.}
+ }</string>
+
+ <!-- Instructions telling the user remaining times when enter SIM PUK view. [CHAR LIMIT=NONE] -->
+ <string name="kg_password_default_puk_message">{count, plural,
+ =1 {SIM is now disabled. Enter PUK code to continue. You have # remaining attempt before SIM becomes permanently unusable. Contact carrier for details.}
+ other {SIM is now disabled. Enter PUK code to continue. You have # remaining attempts before SIM becomes permanently unusable. Contact carrier for details.}
+ }</string>
<!-- Name of the "Default" clock face, which is the clock face that will be shown by default. [CHAR LIMIT=15]-->
<string name="clock_title_default">Default</string>
diff --git a/packages/SystemUI/res/drawable-nodpi/android_13.xml b/packages/SystemUI/res/drawable-nodpi/android_13.xml
new file mode 100644
index 000000000000..edc44ce4eaa3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/android_13.xml
@@ -0,0 +1,42 @@
+<!--
+Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:pathData="M37,39.03l8.58,0l0,33.94"
+ android:strokeWidth="6.2"
+ android:strokeColor="@android:color/system_accent1_800"
+ />
+ <path
+ android:pathData="M53.98,39.03h11.31l-5.59,11.31c6.02,0.96 10.11,6.62 9.15,12.64c-0.85,5.3 -5.38,9.22 -10.74,9.29c-1.38,-0 -2.76,-0.26 -4.05,-0.75"
+ android:strokeWidth="6.2"
+ android:strokeColor="@android:color/system_accent1_800"
+ />
+ <path
+ android:pathData="M37,39.03l8.58,0l0,33.94"
+ android:strokeWidth="1.56"
+ android:strokeColor="@android:color/system_neutral1_100"
+ />
+ <path
+ android:pathData="M53.98,39.03h11.31l-5.59,11.31c6.02,0.96 10.11,6.62 9.15,12.64c-0.85,5.3 -5.38,9.22 -10.74,9.29c-1.38,-0 -2.76,-0.26 -4.05,-0.75"
+ android:strokeWidth="1.56"
+ android:strokeColor="@android:color/system_neutral1_100"
+ />
+
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable-nodpi/android_13_mono.xml b/packages/SystemUI/res/drawable-nodpi/android_13_mono.xml
new file mode 100644
index 000000000000..55c1bcd94831
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/android_13_mono.xml
@@ -0,0 +1,31 @@
+<!--
+Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:pathData="M37,39.03l8.58,0l0,33.94"
+ android:strokeWidth="6.2"
+ android:strokeColor="@android:color/system_accent1_800"
+ />
+ <path
+ android:pathData="M53.98,39.03h11.31l-5.59,11.31c6.02,0.96 10.11,6.62 9.15,12.64c-0.85,5.3 -5.38,9.22 -10.74,9.29c-1.38,-0 -2.76,-0.26 -4.05,-0.75"
+ android:strokeWidth="6.2"
+ android:strokeColor="@android:color/system_accent1_800"
+ />
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable-nodpi/icon.xml b/packages/SystemUI/res/drawable-nodpi/icon.xml
index 997249632709..cdac1f98be30 100644
--- a/packages/SystemUI/res/drawable-nodpi/icon.xml
+++ b/packages/SystemUI/res/drawable-nodpi/icon.xml
@@ -15,5 +15,6 @@ Copyright (C) 2018 The Android Open Source Project
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/icon_bg"/>
- <foreground android:drawable="@drawable/android_12"/>
+ <foreground android:drawable="@drawable/android_13"/>
+ <monochrome android:drawable="@drawable/android_13_mono"/>
</adaptive-icon>
diff --git a/packages/SystemUI/res/drawable-nodpi/icon_bg.xml b/packages/SystemUI/res/drawable-nodpi/icon_bg.xml
index f7b0982dfaf8..231b4b802ecc 100644
--- a/packages/SystemUI/res/drawable-nodpi/icon_bg.xml
+++ b/packages/SystemUI/res/drawable-nodpi/icon_bg.xml
@@ -14,5 +14,5 @@ Copyright (C) 2018 The Android Open Source Project
limitations under the License.
-->
<color xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@color/material_dynamic_primary50" />
+ android:color="@android:color/system_accent3_400" />
diff --git a/packages/SystemUI/res/drawable/privacy_item_circle_media_projection.xml b/packages/SystemUI/res/drawable/privacy_item_circle_media_projection.xml
new file mode 100644
index 000000000000..ac563dee2af5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/privacy_item_circle_media_projection.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@id/background"
+ android:gravity="center"
+ >
+ <shape android:shape="oval">
+ <size
+ android:height="@dimen/ongoing_appops_dialog_circle_size"
+ android:width="@dimen/ongoing_appops_dialog_circle_size"
+ />
+ <solid android:color="@color/privacy_chip_background" />
+ </shape>
+ </item>
+ <item android:id="@id/icon"
+ android:gravity="center"
+ android:width="@dimen/ongoing_appops_dialog_icon_size"
+ android:height="@dimen/ongoing_appops_dialog_icon_size"
+ android:drawable="@drawable/stat_sys_cast"
+ />
+</layer-list> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml b/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml
index 18f870d27772..3d784898f56d 100644
--- a/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml
+++ b/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml
@@ -24,6 +24,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:layout_marginStart="4dp"
+ android:textColor="?android:attr/textColorSecondary"
app:layout_constraintStart_toStartOf="@id/done_button"
app:layout_constraintTop_toBottomOf="@id/done_button" />
diff --git a/packages/SystemUI/res/layout/media_long_press_menu.xml b/packages/SystemUI/res/layout/media_long_press_menu.xml
index 99c5e4707338..a8ddd4cb93ef 100644
--- a/packages/SystemUI/res/layout/media_long_press_menu.xml
+++ b/packages/SystemUI/res/layout/media_long_press_menu.xml
@@ -26,7 +26,7 @@
android:layout_marginStart="@dimen/qs_media_padding"
android:layout_marginEnd="@dimen/qs_media_padding"
android:id="@+id/remove_text"
- android:fontFamily="@*android:string/config_headlineFontFamily"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
@@ -62,7 +62,6 @@
android:layout_marginEnd="@dimen/qs_media_action_spacing"
android:layout_marginBottom="@dimen/qs_media_padding"
app:layout_constrainedWidth="true"
- app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
app:layout_constraintHeight_min="@dimen/min_clickable_item_size"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
@@ -73,6 +72,7 @@
android:id="@+id/dismiss_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
android:layout_gravity="center|top"
style="@style/MediaPlayer.SolidButton"
android:background="@drawable/qs_media_solid_button"
diff --git a/packages/SystemUI/res/layout/media_output_list_item.xml b/packages/SystemUI/res/layout/media_output_list_item.xml
index f79e534670d8..7785a098a0eb 100644
--- a/packages/SystemUI/res/layout/media_output_list_item.xml
+++ b/packages/SystemUI/res/layout/media_output_list_item.xml
@@ -40,6 +40,7 @@
android:paddingStart="0dp"
android:paddingEnd="0dp"
android:background="@null"
+ android:contentDescription="@string/media_output_dialog_accessibility_seekbar"
android:progressDrawable="@drawable/media_output_dialog_seekbar_background"
android:thumb="@null"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index b9153b47995a..9a5c3237f41d 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ligging"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofoon"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"skermopname"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Titelloos"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Bystandmodus"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vergrotingvenster"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Onbekende program"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Hou op uitsaai"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Beskikbare toestelle vir oudio-uitsette."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Hoe uitsaai werk"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Saai uit"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Mense in jou omtrek met versoenbare Bluetooth-toestelle kan na die media luister wat jy uitsaai"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Klaar"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Gekopieer"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Van <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Maak kopieer-UI toe"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Maak gekopieerde teks toe"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Wysig gekopieerde teks"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Wysig gekopieerde prent"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Stuur na toestel in die omtrek"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index c49226afa7ba..a344cf58ee11 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"ካሜራ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"አካባቢ"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"ማይክሮፎን"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"ማያን መቅረጽ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ርዕስ የለም"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ተጠባባቂ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"የማጉያ መስኮት"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"የማይታወቅ መተግበሪያ"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Cast ማድረግ አቁም"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ለኦዲዮ ውጽዓት ተገኚ የሆኑ መሣሪያዎች"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ማሰራጨት እንዴት እንደሚሠራ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ስርጭት"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ተኳሃኝ የብሉቱዝ መሣሪያዎች ያላቸው በአቅራቢያዎ ያሉ ሰዎች እርስዎ እያሰራጩት ያሉትን ሚዲያ ማዳመጥ ይችላሉ"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"ተከናውኗል"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"ተቀድቷል"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"ከ<xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"ዩአይ ቅዳን አሰናብት"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"የተቀዳ ጽሑፍን አሰናብት"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"የተቀዳ ጽሁፍ አርትዕ ያድርጉ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"የተቀዳ ምስል አርትዕ ያድርጉ"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"በአቅራቢያ ወዳለ መሳሪያ ይላኩ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index d3478d355a52..49fe53a5bd7c 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -770,6 +770,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"الكاميرا"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"الموقع"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"الميكروفون"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"تسجيل محتوى الشاشة"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"بلا عنوان"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"وضع الاستعداد"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"نافذة التكبير"</string>
@@ -879,6 +880,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"تطبيق غير معروف"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"إيقاف البث"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"الأجهزة المتاحة لإخراج الصوت"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"كيفية عمل البث"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"البث"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"يمكن للأشخاص القريبين منك الذين لديهم أجهزة متوافقة تتضمّن بلوتوث الاستماع إلى الوسائط التي تبثها."</string>
@@ -974,7 +977,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"تم"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"تم النسخ."</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"من <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"إغلاق واجهة مستخدم النسخ"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"إغلاق حافظة النص المنسوخ"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"تعديل النص المنسوخ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"تعديل الصورة المنسوخة"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"الإرسال إلى جهاز مجاور"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index e9ffa0c68dc0..ea1293f4d3b8 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"Camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"অৱস্থান"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"মাইক্ৰ\'ফ\'ন"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"স্ক্ৰীন ৰেকৰ্ডিং"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"কোনো শিৰোনাম নাই"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ষ্টেণ্ডবাই"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"বিবৰ্ধন ৱিণ্ড’"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"অজ্ঞাত এপ্"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"কাষ্ট বন্ধ কৰক"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"অডিঅ\' আউটপুটৰ বাবে উপলব্ধ ডিভাইচ।"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"সম্প্ৰচাৰ কৰাটোৱে কেনেকৈ কাম কৰে"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"সম্প্ৰচাৰ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"সমিল ব্লুটুথ ডিভাইচৰ সৈতে আপোনাৰ নিকটৱৰ্তী স্থানত থকা লোকসকলে আপুনি সম্প্ৰচাৰ কৰা মিডিয়াটো শুনিব পাৰে"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"হ’ল"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"প্ৰতিলিপি কৰা হ’ল"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g>ৰ পৰা"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"প্ৰতিলিপি কৰা UI অগ্ৰাহ্য কৰক"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"প্ৰতিলিপি কৰা পাঠ অগ্ৰাহ্য কৰক"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"প্ৰতিলিপি কৰা পাঠ সম্পাদনা কৰক"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"প্ৰতিলিপি কৰা প্ৰতিচ্ছবি সম্পাদনা কৰক"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"নিকটৱৰ্তী ডিভাইচলৈ পঠাওক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 0963b763c004..678da7f442ff 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"məkan"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"ekran çəkimi"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Başlıq yoxdur"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Gözləmə rejimi"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Böyütmə Pəncərəsi"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Naməlum tətbiq"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Yayımı dayandırın"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Audio çıxış üçün əlçatan cihazlar."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Yayım necə işləyir"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Yayım"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Uyğun Bluetooth cihazları olan yaxınlığınızdakı insanlar yayımladığınız medianı dinləyə bilər"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Oldu"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopyalandı"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Mənbə: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI kopyalanmasını qapadın"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Kopyalanmış mətni qapadın"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Kopyalanmış mətni redaktə edin"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Kopyalanmış şəkli redaktə edin"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Yaxınlıqdakı cihaza göndərin"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 17be879b0500..4baa16e0b32c 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -755,6 +755,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kameru"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokaciju"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"snimanje ekrana"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez naslova"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje pripravnosti"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Prozor za uvećanje"</string>
@@ -861,6 +862,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nepoznata aplikacija"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zaustavi prebacivanje"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dostupni uređaji za audio izlaz."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako funkcioniše emitovanje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emitovanje"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Ljudi u blizini sa kompatibilnim Bluetooth uređajima mogu da slušaju medijski sadržaj koji emitujete"</string>
@@ -953,7 +956,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Gotovo"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopirano je"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Od: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Odbaci kopiranje korisničkog interfejsa"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Odbaci kopirani tekst"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Izmenite kopirani tekst"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Izmenite kopiranu sliku"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Pošalji na uređaj u blizini"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 70bb2d1e9067..2d59fa4bf2aa 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -760,6 +760,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"геалакацыя"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"мікрафон"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"запіс экрана"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без назвы"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Рэжым чакання"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Акно павелічэння"</string>
@@ -867,6 +868,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Невядомая праграма"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Спыніць трансляцыю"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Даступныя прылады для вываду аўдыя."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Як адбываецца трансляцыя"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Трансляцыя"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Людзі паблізу, у якіх ёсць прылады з Bluetooth, змогуць праслухваць мультымедыйнае змесціва, якое вы трансліруеце"</string>
@@ -960,7 +963,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Гатова"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Скапіравана"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"З праграмы \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Закрыць інтэрфейс капіравання"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Адхіліць устаўку скапіраванага тэксту"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Змяніць скапіраваны тэкст"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Змяніць скапіраваны відарыс"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Адправіць на прыладу паблізу"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index d75bea4f18f8..2d91d4a5622a 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"камерата"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"местополож."</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофона"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"записване на екрана"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Няма заглавие"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Режим на готовност"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Прозорец за увеличение"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Неизвестно приложение"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Спиране на предаването"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Налични устройства за аудиоизход."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Как работи предаването"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Предаване"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Хората в близост със съвместими устройства с Bluetooth могат да слушат мултимедията, която предавате"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Готово"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Копирано"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"От <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Отхвърляне на ПИ за копиране"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Отхвърляне на копирания текст"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Редактиране на копирания текст"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Редактиране на копираното изображение"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Изпращане до устройство в близост"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 254035656617..be51d0630629 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"ক্যামেরা"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"লোকেশন"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"মাইক্রোফোন"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"স্ক্রিন রেকর্ডিং"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"কোনও শীর্ষক নেই"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"স্ট্যান্ডবাই"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"উইন্ডো বড় করে দেখা"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"অজানা অ্যাপ"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"কাস্ট করা বন্ধ করুন"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"অডিও আউটপুটের জন্য উপলভ্য ডিভাইস।"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ব্রডকাস্ট কীভাবে কাজ করে"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"সম্প্রচার করুন"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"আশপাশে লোকজন যাদের মানানসই ব্লুটুথ ডিভাইস আছে, তারা আপনার ব্রডকাস্ট করা মিডিয়া শুনতে পারবেন"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"হয়ে গেছে"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"কপি করা হয়েছে"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> থেকে"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"কপি করা UI বাতিল করুন"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"কপি করা টেক্সট বাতিল করুন"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"কপি করা টেক্সট এডিট করুন"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"কপি করা ছবি এডিট করুন"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"আশেপাশের ডিভাইসে পাঠান"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index d0341d376e39..e8d735c205ec 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -323,10 +323,10 @@
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Lice prepoznato. Pritisnite da otvorite."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Lice prepoznato. Pritisnite ikonu za otklj. da otvorite."</string>
<string-array name="udfps_accessibility_touch_hints">
- <item msgid="1901953991150295169">"Pomicanje ulijevo"</item>
- <item msgid="5558598599408514296">"Pomicanje prema dolje"</item>
- <item msgid="4844142668312841831">"Pomicanje udesno"</item>
- <item msgid="5640521437931460125">"Pomicanje prema gore"</item>
+ <item msgid="1901953991150295169">"Pomjeranje ulijevo"</item>
+ <item msgid="5558598599408514296">"Pomjeranje nadolje"</item>
+ <item msgid="4844142668312841831">"Pomjeranje udesno"</item>
+ <item msgid="5640521437931460125">"Pomjeranje nagore"</item>
</string-array>
<string name="keyguard_retry" msgid="886802522584053523">"Prevucite prema gore da pokušate ponovo"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da koristite NFC"</string>
@@ -755,6 +755,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kameru"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokaciju"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"snimanje ekrana"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez naslova"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje mirovanja"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Prozor za uvećavanje"</string>
@@ -860,7 +861,9 @@
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Da emitirate ovu sesiju, otvorite aplikaciju."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nepoznata aplikacija"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zaustavi emitiranje"</string>
- <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dostupni uređaji za audioizlaz."</string>
+ <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dostupni uređaji za audio izlaz."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako funkcionira emitiranje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emitirajte"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Osobe u vašoj blizini s kompatibilnim Bluetooth uređajima mogu slušati medijske sadržaje koje emitirate"</string>
@@ -953,7 +956,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Gotovo"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopirano"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Iz aplikacije <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Odbaci kopirani korisnički interfejs"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Odbaci kopirani tekst"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Uredi kopirani tekst"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Uredi kopiranu sliku"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Pošalji na uređaj u blizini"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index b249fac55771..a9a115ba4523 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"càmera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ubicació"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"micròfon"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"gravació de pantalla"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sense títol"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Finestra d\'ampliació"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplicació desconeguda"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Atura l\'emissió"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositius disponibles per a la sortida d\'àudio."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Com funciona l\'emissió"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emet"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Les persones properes amb dispositius Bluetooth compatibles poden escoltar el contingut multimèdia que emets"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Fet"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"S\'ha copiat"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"De: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignora la IU de còpia"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Ignora el text copiat"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edita el text que has copiat"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edita la imatge que has copiat"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Envia a un dispositiu proper"</string>
diff --git a/packages/SystemUI/res/values-ca/tiles_states_strings.xml b/packages/SystemUI/res/values-ca/tiles_states_strings.xml
index 242cbd3f2030..aaf19c7c0cc6 100644
--- a/packages/SystemUI/res/values-ca/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ca/tiles_states_strings.xml
@@ -88,7 +88,7 @@
</string-array>
<string-array name="tile_states_color_correction">
<item msgid="2840507878437297682">"No disponible"</item>
- <item msgid="1909756493418256167">"Desactivada"</item>
+ <item msgid="1909756493418256167">"Desactivat"</item>
<item msgid="4531508423703413340">"Activada"</item>
</string-array>
<string-array name="tile_states_inversion">
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index c2fb8139b2e3..0357e171058f 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -760,6 +760,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparát"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"poloha"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"nahrávání obrazovky"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez názvu"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Pohotovostní režim"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Zvětšovací okno"</string>
@@ -867,6 +868,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Neznámá aplikace"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zastavit odesílání"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dostupná zařízení pro zvukový výstup."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Jak vysílání funguje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Vysílání"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Lidé ve vašem okolí s kompatibilními zařízeními Bluetooth mohou poslouchat média, která vysíláte"</string>
@@ -960,7 +963,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Hotovo"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Zkopírováno"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Z aplikace <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Zavřít uživatelské rozhraní kopírování"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Odmítnout zkopírovaný text"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Upravit zkopírovaný text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Upravit zkopírovaný obrázek"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Odeslat do zařízení v okolí"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 43e3aa21ed7f..6d2c3d2d9ee9 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kameraet"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokation"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofonen"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"skærmoptagelse"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ingen titel"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vindue med forstørrelse"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Ukendt app"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop med at caste"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Enheder, der er tilgængelige for lydoutput."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Sådan fungerer udsendelser"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Udsendelse"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Personer i nærheden, som har kompatible Bluetooth-enheder, kan lytte til det medie, du udsender"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Udfør"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopieret"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Fra <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Luk brugerfladen for kopi"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Afvis kopieret tekst"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Rediger kopieret tekst"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Rediger kopieret billede"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send til enhed i nærheden"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 47ed427d9a83..3b11ffc20755 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"Kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"Standort"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"Mikrofon"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"Bildschirmaufzeichnung"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Kein Titel"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vergrößerungsfenster"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unbekannte App"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Streaming beenden"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Für die Audioausgabe verfügbare Geräte."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Funktionsweise von Nachrichten an alle"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Nachricht an alle"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Personen, die in der Nähe sind und kompatible Bluetooth-Geräten haben, können sich die Medien anhören, die du per Nachricht an alle sendest"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Fertig"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopiert"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Von <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Kopieren-Benutzeroberfläche schließen"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Kopierten Text verwerfen"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Kopierten Text bearbeiten"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Kopiertes Bild bearbeiten"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"An Gerät in der Nähe senden"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 092485beee76..e3eea2a4e328 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"κάμερα"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"τοποθεσία"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"μικρόφωνο"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"εγγραφή οθόνης"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Χωρίς τίτλο"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Κατάσταση αναμονής"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Παράθυρο μεγέθυνσης"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Άγνωστη εφαρμογή"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Διακοπή μετάδοσης"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Διαθέσιμες συσκευές για έξοδο ήχου."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Πώς λειτουργεί η μετάδοση"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Μετάδοση"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Οι άνθρωποι με συμβατές συσκευές Bluetooth που βρίσκονται κοντά σας μπορούν να ακούσουν το μέσο που μεταδίδετε."</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Τέλος"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Αντιγράφηκε"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Από <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Παράβλεψη διεπαφής χρήστη αντιγραφής"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Παράβλεψη αντιγραμμένου κειμένου"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Επεξεργασία αντιγραμμένου κειμένου"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Επεξεργασία αντιγραμμένης εικόνας"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Αποστολή σε κοντινή συσκευή"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 819ea0b55512..1777dadde803 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"screen recording"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unknown app"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop casting"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Available devices for audio output."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"People near you with compatible Bluetooth devices can listen to the media that you\'re broadcasting"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Done"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copied"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"From <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dismiss copy UI"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Dismiss copied text"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index bf976826a945..3f04c2e0b2e8 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"screen recording"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unknown app"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop casting"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Available devices for audio output."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"People near you with compatible Bluetooth devices can listen to the media that you\'re broadcasting"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Done"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copied"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"From <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dismiss copy UI"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Dismiss copied text"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 819ea0b55512..1777dadde803 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"screen recording"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unknown app"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop casting"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Available devices for audio output."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"People near you with compatible Bluetooth devices can listen to the media that you\'re broadcasting"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Done"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copied"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"From <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dismiss copy UI"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Dismiss copied text"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 819ea0b55512..1777dadde803 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"screen recording"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unknown app"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop casting"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Available devices for audio output."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"People near you with compatible Bluetooth devices can listen to the media that you\'re broadcasting"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Done"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copied"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"From <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dismiss copy UI"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Dismiss copied text"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index f36bfc13299d..f7415b25d6b6 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‎‏‎‏‎‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‎‎‎‎‎‎‏‎‏‏‎‏‏‏‏‎‎‎camera‎‏‎‎‏‎"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‏‏‏‎‏‏‏‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‏‏‏‏‎location‎‏‎‎‏‎"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‏‎‏‎‎‏‎‏‎‎‎‎‎‎‎‏‎‎‏‎‎‏‏‎‎‎microphone‎‏‎‎‏‎"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‎‏‏‎‏‏‏‎‎‏‏‎‎‏‏‎‏‏‎‎‏‎‎‏‎‏‏‎‏‎‏‎‏‎‏‎‏‏‎‏‏‏‏‏‎‎‏‏‎‏‏‎screen recording‎‏‎‎‏‎"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‎‏‎‎‏‎‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‎‎‏‏‎‎‎‏‏‏‎‎‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎No title‎‏‎‎‏‎"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‏‎‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‎‏‎‎‏‏‎‏‏‏‎‎‏‎‏‎Standby‎‏‎‎‏‎"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‏‏‎‏‎‎‏‎‏‏‎‏‏‏‎‏‎Magnification Window‎‏‎‎‏‎"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‏‎‏‏‎‎‎‏‏‎‎‎‏‎‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎Unknown app‎‏‎‎‏‎"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‏‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‎‏‎Stop casting‎‏‎‎‏‎"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‏‏‎‎‎‏‏‏‎‎‎‏‎‏‎‏‏‎‎‎‏‎‏‏‎‎‏‎‏‎‏‏‎‏‎‏‎‎‎‎‎‏‎‏‏‎‏‎‏‎‎‎‎‎Available devices for audio output.‎‏‎‎‏‎"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‎‎‏‎‏‎‎‎‎‏‎‎‏‏‏‎‏‏‏‎‏‎‏‎‎‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎‏‏‏‎‎‏‏‏‏‏‏‎‎How broadcasting works‎‏‎‎‏‎"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‎‏‎‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‏‏‏‎‎‎‏‏‏‏‎‏‏‏‎Broadcast‎‏‎‎‏‎"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‏‎‏‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‎‎‏‎‏‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‎‎People near you with compatible Bluetooth devices can listen to the media you\'re broadcasting‎‏‎‎‏‎"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‏‎‏‏‏‎‎‎‏‏‎‏‏‏‎‎‎‏‎‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‎‏‏‎‎‎‎‏‏‏‎‎‎‎‏‎‎‏‎Done‎‏‎‎‏‎"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‏‏‎‏‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‎‎‎‏‏‎Copied‎‏‎‎‏‎"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‏‎‎‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎From ‎‏‎‎‏‏‎<xliff:g id="APPNAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‎‎‏‎‏‎‎‏‎‎‎‎‏‎‏‏‎‎‎‎‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‎Dismiss copy UI‎‏‎‎‏‎"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‏‏‏‏‎‏‎‎‎‏‏‎‎‏‎‎‎‏‎‎‎‎‏‎‎‏‎‎‎‎‏‎‏‏‎‎‎‎‏‎‎‎‏‏‏‎‏‏‏‎‎Dismiss copied text‎‏‎‎‏‎"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‎‏‏‎‏‎‏‏‎‏‎‎‏‏‎‎‎‏‎‎‎‎‎‏‎‏‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎‎‎‏‏‎‏‏‏‎Edit copied text‎‏‎‎‏‎"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‎‏‏‎‏‎‎‏‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‏‎‎Edit copied image‎‏‎‎‏‎"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‎‎‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‎‎‏‏‎‏‎‎‏‎‎Send to nearby device‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index c8abf0b462d9..509240e8961a 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"cámara"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ubicación"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"micrófono"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"Grabación de pant."</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sin título"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ventana de ampliación"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App desconocida"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Detener transmisión"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositivos disponibles para salida de audio."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cómo funciona la transmisión"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmisión"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Las personas cercanas con dispositivos Bluetooth compatibles pueden escuchar el contenido multimedia que transmites"</string>
@@ -906,7 +909,7 @@
<string name="person_available" msgid="2318599327472755472">"Disponible"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema al leer el medidor de batería"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Presiona para obtener más información"</string>
- <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No se estableció alarma"</string>
+ <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No establecida"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor de huellas dactilares"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ingresar al dispositivo"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Listo"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Se copió"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"De <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Descartar la copia de la IU"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Descartar el texto copiado"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar el texto copiado"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar la imagen copiada"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar a dispositivos cercanos"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index c9c7f7c63b8c..a7048839ab4a 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"cámara"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ubicación"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"micrófono"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"grabación de pantalla"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sin título"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ventana de ampliación"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplicación desconocida"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Dejar de enviar contenido"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositivos disponibles para la salida de audio."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cómo funciona la emisión"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emisión"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Las personas cercanas con dispositivos Bluetooth compatibles pueden escuchar el contenido multimedia que emites"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Hecho"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiado"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"De <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Cerrar la interfaz de copia"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Descartar texto copiado"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imagen copiada"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar a dispositivo cercano"</string>
diff --git a/packages/SystemUI/res/values-es/tiles_states_strings.xml b/packages/SystemUI/res/values-es/tiles_states_strings.xml
index e1082bf4e48c..36a542a5ad67 100644
--- a/packages/SystemUI/res/values-es/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es/tiles_states_strings.xml
@@ -63,8 +63,8 @@
</string-array>
<string-array name="tile_states_rotation">
<item msgid="4578491772376121579">"No disponible"</item>
- <item msgid="5776427577477729185">"Desactivado"</item>
- <item msgid="7105052717007227415">"Activado"</item>
+ <item msgid="5776427577477729185">"Desactivada"</item>
+ <item msgid="7105052717007227415">"Activada"</item>
</string-array>
<string-array name="tile_states_bt">
<item msgid="5330252067413512277">"No disponible"</item>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 73dfbc77f254..66933fcf5e04 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kaamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"asukoht"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"ekraanikuva salvest."</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Pealkiri puudub"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ooterežiim"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Suurendamisaken"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Tundmatu rakendus"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Lõpeta ülekanne"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Saadaolevad seadmed heli esitamiseks."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kuidas ülekandmine toimib?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Ülekanne"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Teie läheduses olevad inimesed, kellel on ühilduvad Bluetooth-seadmed, saavad kuulata teie ülekantavat meediat"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Valmis"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopeeritud"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Rakendusest <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Koopiast loobumise kasutajaliides"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Loobu kopeeritud tekstist"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Muuda kopeeritud teksti"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Muuda kopeeritud pilti"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Saada läheduses olevasse seadmesse"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 41e47dd7f799..39de3677fbe6 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"kokapena"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofonoa"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"pantaila-grabaketa"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ez du izenik"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Egonean"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Lupa-leihoa"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplikazio ezezaguna"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Gelditu igorpena"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Audio-irteerarako gailu erabilgarriak."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Nola funtzionatzen dute iragarpenek?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Iragarri"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Bluetooth bidezko gailu bateragarriak dituzten inguruko pertsonek iragartzen ari zaren multimedia-edukia entzun dezakete"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Eginda"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopiatu da"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Jatorria: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Kopiatutako UIa baztertzeko botoia"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Baztertu kopiatutako testua"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editatu kopiatutako testua"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editatu kopiatutako irudia"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Bidali inguruko gailu batera"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 2106bdcf5f89..04b4a9e0af0a 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"دوربین"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"مکان"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"میکروفون"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"ضبط صفحه‌نمایش"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"بدون عنوان"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"آماده‌به‌کار"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"پنجره بزرگ‌نمایی"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"برنامه ناشناس"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"توقف ارسال محتوا"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"دستگاه‌های دردسترس برای خروجی صدا."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"همه‌فرتستی چطور کار می‌کند"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"همه‌فرستی"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"‏افرادی که در اطرافتان دستگاه‌های Bluetooth سازگار دارند می‌توانند به رسانه‌ای که همه‌فرستی می‌کنید گوش کنند"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"تمام"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"کپی شد"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"از <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"رد کردن رابط کاربری کپی کردن"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"رد شدن نوشتار کپی‌شده"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"ویرایش نوشتار کپی‌شده"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"ویرایش تصویر کپی‌شده"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ارسال به دستگاهی در اطراف"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index b3a3c05eee64..9c4a6cacc207 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"sijainti"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofoni"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"näytön tallennus"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ei nimeä"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Virransäästötila"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Suurennusikkuna"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Tuntematon sovellus"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Lopeta striimaus"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Käytettävissä olevat audiolaitteet"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Miten lähetys toimii"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Lähetys"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Lähistöllä olevat ihmiset, joilla on yhteensopiva Bluetooth-laite, voivat kuunnella lähettämääsi mediaa"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Valmis"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopioitu"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Lähde: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Hylkää kopioitu UI"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Hylkää kopioitu teksti"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Muokkaa kopioitua tekstiä"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Muokkaa kopioitua kuvaa"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Lähetä lähellä olevaan laitteeseen"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 24d4967b45b2..a0abc35aaad4 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"appareil photo"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"position"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"enregistrement d\'écran"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sans titre"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Veille"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Fenêtre d\'agrandissement"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Application inconnue"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Arrêter la diffusion"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Appareils disponibles pour la sortie audio."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Fonctionnement de la diffusion"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Diffusion"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Les personnes à proximité disposant d\'appareils Bluetooth compatibles peuvent écouter le contenu multimédia que vous diffusez"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"OK"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copié"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"À partir de <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignorer la copie de l\'IU"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Ignorer le texte copié"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Modifier le texte copié"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Modifier l\'image copiée"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Envoyer à un appareil à proximité"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 29ef79f40d2b..25bccba384fe 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -320,10 +320,12 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Déverrouillé par visage. Appuyez pour ouvrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Visage reconnu. Appuyez pour ouvrir."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Visage reconnu. Appuyez sur l\'icône de déverrouillage pour ouvrir."</string>
- <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
- <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
- <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
- <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
+ <string-array name="udfps_accessibility_touch_hints">
+ <item msgid="1901953991150295169">"Déplacer vers la gauche"</item>
+ <item msgid="5558598599408514296">"Déplacer vers le bas"</item>
+ <item msgid="4844142668312841831">"Déplacer vers la droite"</item>
+ <item msgid="5640521437931460125">"Déplacer vers le haut"</item>
+ </string-array>
<string name="keyguard_retry" msgid="886802522584053523">"Balayez l\'écran vers le haut pour réessayer"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour pouvoir utiliser la NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string>
@@ -699,10 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alertes"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batterie"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Captures d\'écran"</string>
- <!-- no translation found for notification_channel_instant (7556135423486752680) -->
- <skip />
- <!-- no translation found for notification_channel_setup (7660580986090760350) -->
- <skip />
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Applis instantanées"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Configurer"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Espace de stockage"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Astuces"</string>
<string name="instant_apps" msgid="8337185853050247304">"Applis instantanées"</string>
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"l\'appareil photo"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"la position"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"le micro"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"enregistrement écran"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sans titre"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Mode Veille imminent"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Fenêtre d\'agrandissement"</string>
@@ -854,7 +855,8 @@
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Pour caster cette session, veuillez ouvrir l\'appli."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Appli inconnue"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Arrêter la diffusion"</string>
- <!-- no translation found for media_output_dialog_accessibility_title (4681741064190167888) -->
+ <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Appareils disponibles pour la sortie audio."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Fonctionnement des annonces"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Annonce"</string>
@@ -947,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"OK"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copié"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"De <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Désactiver l\'interface de copie"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Ignorer le texte copié"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Modifier le texte copié"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Modifier l\'image copiée"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Envoyer à un appareil à proximité"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 148366c1e4f9..f83e181a622c 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"a cámara"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"a localiz."</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"o micrófono"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"gravación pantalla"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sen título"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Modo de espera"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ventá de superposición"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplicación descoñecida"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Deter emisión"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositivos dispoñibles para a saída de audio."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funcionan as difusións?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Difusión"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"As persoas que estean preto de ti e que dispoñan de dispositivos Bluetooth compatibles poden escoitar o contido multimedia que difundas"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Feito"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiouse"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"De <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignorar interface de copia"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Ignorar texto copiado"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imaxe copiada"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar a dispositivo próximo"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 7ba9a992a043..940f3c5734b4 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"કૅમેરા"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"સ્થાન"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"માઇક્રોફોન"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"સ્ક્રીન રેકોર્ડિંગ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"કોઈ શીર્ષક નથી"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"સ્ટૅન્ડબાય"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"વિસ્તૃતીકરણ વિંડો"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"અજાણી ઍપ"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"કાસ્ટ કરવાનું રોકો"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ઑડિયો આઉટપુટ માટે ઉપલબ્ધ ડિવાઇસ."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"બ્રોડકાસ્ટ પ્રક્રિયાની કામ કરવાની રીત"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"બ્રોડકાસ્ટ કરો"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"સુસંગત બ્લૂટૂથ ડિવાઇસ ધરાવતા નજીકના લોકો તમે જે મીડિયા બ્રોડકાસ્ટ કરી રહ્યાં છો તે સાંભળી શકે છે"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"થઈ ગયું"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"કૉપિ કરવામાં આવી"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g>માંથી"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"\'UI | યૂઝર ઇન્ટરફેસ (UI) કૉપિ કરો\'ને છોડી દો"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"કૉપિ કરેલી ટેક્સ્ટ છોડી દો"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"કૉપિ કરેલી ટેક્સ્ટમાં ફેરફાર કરો"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"કૉપિ કરેલી છબીમાં ફેરફાર કરો"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"નજીકના ડિવાઇસને મોકલો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 842aa6af9b7d..cc5f71aaa399 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"कैमरा"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"जगह"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"माइक्रोफ़ोन"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"स्क्रीन रिकॉर्डिंग"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"कोई शीर्षक नहीं"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टैंडबाई"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"स्क्रीन को बड़ा करके दिखाने वाली विंडो"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"अनजान ऐप्लिकेशन"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"कास्टिंग करना रोकें"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ऑडियो आउटपुट के लिए उपलब्ध डिवाइस."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ब्रॉडकास्ट करने की सुविधा कैसे काम करती है"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ब्रॉडकास्ट करें"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"आपके आस-पास मौजूद लोग, ब्रॉडकास्ट किए जा रहे मीडिया को सुन सकते हैं. हालांकि, इसके लिए उनके पास ऐसे ब्लूटूथ डिवाइस होने चाहिए जिन पर मीडिया चलाया जा सके"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"हो गया"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"कॉपी किया गया"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> से"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"कॉपी किया गया यूज़र इंटरफ़ेस (यूआई) खारिज करें"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"कॉपी किए गए टेक्स्ट को खारिज करें"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"कॉपी किए गए टेक्स्ट में बदलाव करें"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"कॉपी की गई इमेज में बदलाव करें"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"कॉन्टेंट को आस-पास मौजूद डिवाइस पर भेजें"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 77ca45f52fa3..3b4120e421de 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -755,6 +755,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparat"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokaciju"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"snimanje zaslona"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez naslova"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje mirovanja"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Prozor za povećavanje"</string>
@@ -861,6 +862,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nepoznata aplikacija"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zaustavi emitiranje"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dostupni uređaji za audioizlaz."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako emitiranje funkcionira"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Emitiranje"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Osobe u blizini s kompatibilnim Bluetooth uređajima mogu slušati medije koje emitirate"</string>
@@ -953,7 +956,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Gotovo"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopirano"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Iz aplikacije <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Odbaci kopiranje korisničkog sučelja"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Odbaci kopirani tekst"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Uredi kopirani tekst"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Uredi kopiranu sliku"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Pošalji uređaju u blizini"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 4708f98f6046..cf596c0c7ec7 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"helyadatok"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"képernyőrögzítés"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nincs cím"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Készenléti mód"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Nagyítás ablaka"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Ismeretlen alkalmazás"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Átküldés leállítása"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Rendelkezésre álló eszközök a hangkimenethez."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"A közvetítés működése"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Közvetítés"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"A közelben tartózkodó, kompatibilis Bluetooth-eszközzel rendelkező személyek meghallgathatják az Ön közvetített médiatartalmait"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Kész"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Másolva"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Forrás: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Másolási UI elvetése"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Vágólapra másolt szöveg elvetése"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Vágólapra másolt szöveg szerkesztése"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Vágólapra másolt kép szerkesztése"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Küldés közeli eszközre"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 7f53aa88a440..49b2d0084286 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"տեսախցիկը"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"վայրը"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"խոսափողը"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"էկրանի տեսագրում"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Անանուն"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Սպասման ռեժիմ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Խոշորացման պատուհան"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Անհայտ հավելված"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Կանգնեցնել հեռարձակումը"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Հասանելի սարքեր ձայնի արտածման համար։"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Ինչպես է աշխատում հեռարձակումը"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Հեռարձակում"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Ձեր մոտակայքում գտնվող՝ համատեղելի Bluetooth սարքերով մարդիկ կարող են լսել մեդիա ֆայլերը, որոնք դուք հեռարձակում եք։"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Պատրաստ է"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Պատճենվեց"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> հավելվածից"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Փակել պատճենների միջերեսը"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Հեռացնել պատճենված տեքստը"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Փոփոխել պատճենված տեքստը"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Փոփոխել պատճենված պատկերը"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Ուղարկել մոտակա սարքի"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index c2bf59b1837e..ffa26745e4af 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokasi"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"perekaman layar"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Tanpa judul"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Siaga"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Jendela Pembesaran"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplikasi tidak dikenal"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Hentikan transmisi"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Perangkat yang tersedia untuk output audio."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cara kerja siaran"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Siaran"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Orang di dekat Anda dengan perangkat Bluetooth yang kompatibel dapat mendengarkan media yang sedang Anda siarkan"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Selesai"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Disalin"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Dari <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Tutup UI salin"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Tutup teks yang disalin"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit teks yang disalin"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit gambar yang disalin"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Kirim ke perangkat di sekitar"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index eb075f2dec98..f11cb5a69ea7 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"myndavél"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"staðsetning"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"hljóðnemi"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"skjáupptaka"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Enginn titill"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Biðstaða"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Stækkunargluggi"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Óþekkt forrit"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stöðva útsendingu"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Tæki í boði fyrir hljóðúttak."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Svona virkar útsending"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Útsending"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Fólk nálægt þér með samhæf Bluetooth-tæki getur hlustað á efnið sem þú sendir út"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Lokið"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Afritað"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Frá <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Loka afriti notendaviðmóts"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Hunsa afritaðan texta"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Breyta afrituðum texta"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Breyta afritaðri mynd"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Senda í nálægt tæki"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index dcbd6afab1d1..3bb37dc89565 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"fotocamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"posizione"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microfono"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"Registraz. schermo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Senza titolo"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Finestra ingrandimento"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App sconosciuta"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Interrompi trasmissione"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositivi disponibili per l\'uscita audio."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Come funziona la trasmissione"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Annuncio"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Le persone vicine a te che hanno dispositivi Bluetooth compatibili possono ascoltare i contenuti multimediali che stai trasmettendo"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Fine"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiato"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Da <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignora copia UI"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Ignora il testo copiato"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Modifica testo copiato"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Modifica immagine copiata"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Invia a dispositivo nelle vicinanze"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 25a8bee68ea6..f04106937ea3 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -760,6 +760,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"מצלמה"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"מיקום"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"מיקרופון"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"הקלטת המסך"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ללא שם"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"המתנה"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"חלון הגדלה"</string>
@@ -867,6 +868,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"אפליקציה לא ידועה"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"‏עצירת ההעברה (casting)"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"מכשירים זמינים לפלט אודיו."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"הסבר על שידורים"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"שידור"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"‏אנשים בקרבת מקום עם מכשירי Bluetooth תואמים יכולים להאזין למדיה שמשודרת על ידך"</string>
@@ -960,7 +963,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"סיום"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"הועתק"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"המקור: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"ביטול של העתקת ממשק המשתמש"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"מחיקה של הטקסט שהועתק"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"עריכת הטקסט שהועתק"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"עריכת התמונה שהועתקה"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"שליחה למכשיר בקרבת מקום"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 5414c8d66d59..e80cb9cba74e 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"カメラ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"現在地情報"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"マイク"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"画面の録画"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"タイトルなし"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"スタンバイ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"拡大ウィンドウ"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"不明なアプリ"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"キャストを停止"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"音声出力ができるデバイスです。"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ブロードキャストの仕組み"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ブロードキャスト"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Bluetooth 対応デバイスを持っている付近のユーザーは、あなたがブロードキャストしているメディアを聴けます"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"完了"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"コピーしました"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> から"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"コピー UI を閉じる"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"コピーしたテキストを閉じる"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"コピーしたテキストを編集"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"コピーした画像を編集"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"付近のデバイスに送信"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 691ad8d44729..c91d867122fd 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"კამერა"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"მდებარეობა"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"მიკროფონი"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"ეკრანის ჩაწერა"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"უსათაურო"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"მოლოდინის რეჟიმი"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"გადიდების ფანჯარა"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"უცნობი აპი"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ტრანსლირების შეწყვეტა"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ხელმისაწვდომი მოწყობილობები გამომავალი აუდიოსთვის."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ტრანსლირების მუშაობის პრინციპი"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ტრანსლაცია"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"თქვენთან ახლოს მყოფ ხალხს თავსებადი Bluetooth მოწყობილობით შეუძლიათ თქვენ მიერ ტრანსლირებული მედიის მოსმენა"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"მზადაა"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"კოპირებულია"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g>-დან"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"მომხმარებლის ინტერფეისის ასლის გაუქმება"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"კოპირებული ტექსტის უარყოფა"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"კოპირებული ტექსტის რედაქტირება"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"კოპირებული სურათის რედაქტირება"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ახლომახლო მოწყობილობაზე გაგზავნა"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index b0ca261dd5f4..57a6d178d11f 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"геодерек"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"экранды бейнеге жазу"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Атауы жоқ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Күту режимі"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ұлғайту терезесі"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Белгісіз қолданба"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Трансляцияны тоқтату"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Аудио шығыс үшін қолжетімді құрылғылар бар."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Тарату қалай жүзеге асады"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Тарату"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Үйлесімді Bluetooth құрылғылары бар маңайдағы адамдар сіз таратып жатқан медиамазмұнды тыңдай алады."</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Дайын"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Көшірілді"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> қолданбасынан"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Көшіру интерфейсін жабу"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Көшірілген мәтінді жою"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Көшірілген мәтінді өңдеу"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Көшірілген суретті өңдеу"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Маңайдағы құрылғыға жіберу"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 381e679df802..1f723c52caa2 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"កាមេរ៉ា"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ទីតាំង"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"មីក្រូហ្វូន"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"ការថតវីដេអូអេក្រង់"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"គ្មាន​ចំណងជើង"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ផ្អាក​ដំណើរការ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"វិនដូ​ការពង្រីក"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"កម្មវិធី​ដែលមិន​ស្គាល់"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"បញ្ឈប់ការភ្ជាប់"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ឧបករណ៍​ដែលអាច​ប្រើបាន​សម្រាប់ឧបករណ៍​បញ្ចេញ​សំឡេង។"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"របៀបដែលការផ្សាយដំណើរការ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ការ​ផ្សាយ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"មនុស្សនៅជិត​អ្នកដែលមាន​ឧបករណ៍ប៊្លូធូស​ត្រូវគ្នា​អាចស្តាប់​មេឌៀ​ដែលអ្នកកំពុងផ្សាយបាន"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"រួចរាល់"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"បានចម្លង"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"ពី <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"ច្រានចោល UI ចម្លង"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"ច្រានចោលអត្ថបទដែលបានចម្លង"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"កែអត្ថបទ​ដែលបានចម្លង"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"កែរូបភាព​ដែលបានចម្លង"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ផ្ញើទៅ​ឧបករណ៍​នៅជិត"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index e5723979f624..55989b151ab0 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"ಕ್ಯಾಮರಾ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ಸ್ಥಳ"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"ಮೈಕ್ರೋಫೋನ್‌"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ಯಾವುದೇ ಶೀರ್ಷಿಕೆಯಿಲ್ಲ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ಸ್ಟ್ಯಾಂಡ್‌ಬೈ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ವರ್ಧನೆಯ ವಿಂಡೋ"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"ಅಪರಿಚಿತ ಆ್ಯಪ್"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ಬಿತ್ತರಿಸುವುದನ್ನು ನಿಲ್ಲಿಸಿ"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ಆಡಿಯೋ ಔಟ್‌ಪುಟ್‌ಗಾಗಿ ಲಭ್ಯವಿರುವ ಸಾಧನಗಳು."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ಪ್ರಸಾರವು ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ಪ್ರಸಾರ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ಹೊಂದಾಣಿಕೆಯಾಗುವ ಬ್ಲೂಟೂತ್ ಸಾಧನಗಳನ್ನು ಹೊಂದಿರುವ ಸಮೀಪದಲ್ಲಿರುವ ಜನರು ನೀವು ಪ್ರಸಾರ ಮಾಡುತ್ತಿರುವ ಮಾಧ್ಯಮವನ್ನು ಆಲಿಸಬಹುದು"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"ಮುಗಿದಿದೆ"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"ನಕಲಿಸಲಾಗಿದೆ"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> ನಿಂದ"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI ನಕಲನ್ನು ವಜಾಗೊಳಿಸಿ"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"ನಕಲಿಸಿದ ಪಠ್ಯವನ್ನು ವಜಾಗೊಳಿಸಿ"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"ನಕಲಿಸಿದ ಪಠ್ಯವನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"ನಕಲಿಸಿದ ಚಿತ್ರವನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ಸಮೀಪದಲ್ಲಿರುವ ಸಾಧನಕ್ಕೆ ಕಳುಹಿಸಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index ec1cd02969a1..ad4ccdc09a53 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"카메라"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"위치"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"마이크"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"화면 녹화"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"제목 없음"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"대기"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"확대 창"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"알 수 없는 앱"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"전송 중지"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"오디오 출력에 사용 가능한 기기입니다."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"브로드캐스팅 작동 원리"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"브로드캐스트"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"호환되는 블루투스 기기를 가진 근처의 사용자가 내가 브로드캐스트 중인 미디어를 수신 대기할 수 있습니다."</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"완료"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"복사됨"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"복사한 위치: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI 복사 닫기"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"복사된 텍스트 닫기"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"복사된 텍스트 편집"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"복사된 이미지 편집"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"근처 기기에 전송"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 55fa0be34383..cc70d00476ac 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"жайгашкан жер"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"экранды жаздыруу"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Аталышы жок"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Көшүү режими"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Чоңойтуу терезеси"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Белгисиз колдонмо"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Тышкы экранга чыгарууну токтотуу"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Аудио чыгаруу үчүн жеткиликтүү түзмөктөр."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Кабарлоо кантип иштейт"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Кабарлоо"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Шайкеш Bluetooth түзмөктөрү болгон жакын жердеги кишилер кабарлап жаткан медиаңызды уга алышат"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Бүттү"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Көчүрүлдү"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> колдонмосунан"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Көчүрмөнү жабуу интерфейси"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Көчүрүлгөн текстти жабуу"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Көчүрүлгөн текстти түзөтүү"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Көчүрүлгөн сүрөттү түзөтүү"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Жакын жердеги түзмөккө жөнөтүү"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index cc200ce9fb90..e2ecaaa2b17f 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"ກ້ອງຖ່າຍຮູບ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ສະຖານທີ່"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"ໄມໂຄຣໂຟນ"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"ການບັນທຶກໜ້າຈໍ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ບໍ່ມີຊື່"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ສະແຕນບາຍ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ໜ້າຈໍການຂະຫຍາຍ"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"ແອັບທີ່ບໍ່ຮູ້ຈັກ"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ຢຸດການສົ່ງສັນຍານ"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ອຸປະກອນທີ່ສາມາດໃຊ້ໄດ້ສຳລັບເອົ້າພຸດສຽງ."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ການອອກອາກາດເຮັດວຽກແນວໃດ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ອອກອາກາດ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ຄົນທີ່ຢູ່ໃກ້ທ່ານທີ່ມີອຸປະກອນ Bluetooth ທີ່ເຂົ້າກັນໄດ້ຈະສາມາດຟັງມີເດຍທີ່ທ່ານກຳລັງອອກອາກາດຢູ່ໄດ້"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"ແລ້ວໆ"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"ສຳເນົາແລ້ວ"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"ຈາກ <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"ປິດການສຳເນົາສ່ວນຕິດຕໍ່ຜູ້ໃຊ້ໄວ້"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"ປິດຂໍ້ຄວາມທີ່ສຳເນົາໄວ້"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"ແກ້ໄຂຂໍ້ຄວາມທີ່ສຳເນົາແລ້ວ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"ແກ້ໄຂຮູບທີ່ສຳເນົາແລ້ວ"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ສົ່ງໄປຫາອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 491cb175e91b..effd57278432 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -760,6 +760,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparatą"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"vietovę"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofoną"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"ekrano įrašymas"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nėra pavadinimo"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Budėjimo laikas"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Didinimo langas"</string>
@@ -867,6 +868,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nežinoma programa"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Sustabdyti perdavimą"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Pasiekiami garso išvesties įrenginiai."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kaip veikia transliacija"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transliacija"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Netoliese esantys žmonės, turintys suderinamus „Bluetooth“ įrenginius, gali klausyti jūsų transliuojamos medijos"</string>
@@ -960,7 +963,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Atlikta"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Nukopijuota"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Iš „<xliff:g id="APPNAME">%1$s</xliff:g>“"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Atsisakyti kopijavimo NS"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Atsisakyti nukopijuoto teksto"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Redaguoti nukopijuotą tekstą"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Redaguoti nukopijuotą vaizdą"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Siųsti į įrenginį netoliese"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 0e37594eb7d5..aa4aa7f43e6b 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -755,6 +755,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"atrašanās vieta"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofons"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"ekrāna ierakstīšana"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nav nosaukuma"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Gaidstāve"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Palielināšanas logs"</string>
@@ -861,6 +862,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nezināma lietotne"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Apturēt apraidi"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Audio izvadei pieejamās ierīces."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kā darbojas apraide"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Apraide"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Tuvumā esošās personas ar saderīgām Bluetooth ierīcēm var klausīties jūsu apraidīto multivides saturu."</string>
@@ -953,7 +956,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Gatavs"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Nokopēts"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"No lietotnes <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Noraidīt ar kopēšanu saistīto lietotāja saskarnes elementu"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Nerādīt kopēto tekstu"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Rediģēt nokopēto tekstu"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Rediģēt nokopēto attēlu"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Sūtīt uz tuvumā esošu ierīci"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index b6826afcaae7..8049bd4ae1d0 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"локација"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"снимање на екранот"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без наслов"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Подготвеност"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Прозорец за зголемување"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Непозната апликација"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Сопри со емитување"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Достапни уреди за аудиоизлез."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Како функционира емитувањето"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Емитување"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Луѓето во ваша близина со компатибилни уреди со Bluetooth може да ги слушаат аудиозаписите што ги емитувате"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Готово"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Копирано"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Од <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Отфрли го корисничкиот интерфејс за копирање"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Отфрли го копираниот текст"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Изменете го копираниот текст"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Изменете ја копираната слика"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Испратете до уред во близина"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index ebf8fd64cb2b..ebb9cbe2e0bf 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"ക്യാമറ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ലൊക്കേഷന്‍"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"മൈക്രോഫോൺ"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"സ്ക്രീൻ റെക്കോർഡിംഗ്"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"പേരില്ല"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"സ്‌റ്റാൻഡ്‌ബൈ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"മാഗ്നിഫിക്കേഷൻ വിൻഡോ"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"അജ്ഞാതമായ ആപ്പ്"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"കാസ്റ്റ് ചെയ്യുന്നത് നിർത്തുക"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ഓഡിയോ ഔട്ട്‌പുട്ടിന് ലഭ്യമായ ഉപകരണങ്ങൾ."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ബ്രോഡ്‌കാസ്‌റ്റ് എങ്ങനെയാണ് പ്രവർത്തിക്കുന്നത്"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ബ്രോഡ്‌കാസ്റ്റ്"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"അനുയോജ്യമായ Bluetooth ഉപകരണങ്ങളോടെ സമീപമുള്ള ആളുകൾക്ക് നിങ്ങൾ ബ്രോഡ്‌കാസ്‌റ്റ് ചെയ്യുന്ന മീഡിയ കേൾക്കാനാകും"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"പൂർത്തിയായി"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"പകർത്തി"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> എന്നതിൽ നിന്ന്"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"പകർപ്പ് UI ഡിസ്‌മിസ് ചെയ്യുക"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"പകർത്തിയ ടെക്സ്റ്റ് ഡിസ്‌മിസ് ചെയ്യുക"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"പകർത്തിയ ടെക്സ്റ്റ് എഡിറ്റ് ചെയ്യുക"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"പകർത്തിയ ചിത്രം എഡിറ്റ് ചെയ്യുക"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"സമീപത്തുള്ള ഉപകരണത്തിലേക്ക് അയയ്ക്കുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 06ef868f9249..1da11746473c 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"камер"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"байршил"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"дэлгэцийн бичлэг"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Гарчиггүй"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Зогсолтын горим"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Томруулалтын цонх"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Үл мэдэгдэх апп"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Дамжуулахыг зогсоох"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Аудио гаралт хийх боломжтой төхөөрөмжүүд."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Нэвтрүүлэлт хэрхэн ажилладаг вэ?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Нэвтрүүлэлт"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Тохиромжтой Bluetooth төхөөрөмжүүдтэй таны ойролцоох хүмүүс таны нэвтрүүлж буй медиаг сонсох боломжтой"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Болсон"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Хууллаа"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g>-с"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Хуулах UI-г хаах"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Хуулсан текстийг үл хэрэгсэх"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Хуулсан текстийг засах"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Хуулсан зургийг засах"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Ойролцоох төхөөрөмж рүү илгээх"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 739e0fd5c153..dfed3e39a49d 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -311,7 +311,7 @@
<string name="zen_alarms_introduction" msgid="3987266042682300470">"अलार्म व्यतिरिक्त तुम्हाला कोणत्याही आवाज आणि कंपनांचा व्यत्त्यय आणला जाणार नाही. तरीही तुम्ही प्ले करायचे ठरवलेले कोणतेही संगीत, व्हिडिओ आणि गेमचे आवाज ऐकू शकतात."</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"सानुकूलित करा"</string>
<string name="zen_silence_introduction_voice" msgid="853573681302712348">"हे अलार्म, संगीत, व्हिडिओ आणि गेमसह, सर्व आवाज आणि कंपने ब्लॉक करते. तरीही तुम्ही फोन कॉल करू शकतात."</string>
- <string name="zen_silence_introduction" msgid="6117517737057344014">"हे अलार्म, संगीत, व्हिडिओ आणि गेम यासह, सर्व आवाज आणि कंपने अवरोधित करते."</string>
+ <string name="zen_silence_introduction" msgid="6117517737057344014">"हे अलार्म, संगीत, व्हिडिओ आणि गेम यांसह, सर्व आवाज आणि व्हायब्रेशन ब्लॉक करते."</string>
<string name="notification_tap_again" msgid="4477318164947497249">"उघडण्यासाठी पुन्हा टॅप करा"</string>
<string name="tap_again" msgid="1315420114387908655">"पुन्हा टॅप करा"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"उघडण्यासाठी वर स्वाइप करा"</string>
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"स्थान"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"मायक्रोफोन"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"स्क्रीन रेकॉर्डिंग"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"शीर्षक नाही"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टँडबाय"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"मॅग्निफिकेशन विंडो"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"अज्ञात अ‍ॅप"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"कास्ट करणे थांबवा"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ऑडिओ आउटपुटसाठी उपलब्ध डिव्हाइस."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ब्रॉडकास्टिंग कसे काम करते"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ब्रॉडकास्ट करा"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"कंपॅटिबिल ब्लूटूथ डिव्‍हाइस असलेले तुमच्या जवळपासचे लोक हे तुम्ही ब्रॉडकास्ट करत असलेला मीडिया ऐकू शकतात"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"पूर्ण झाले"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"कॉपी केले"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> वरून"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"कॉपी केलेले UI डिसमिस करा"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"कॉपी केलेला मजकूर डिसमिस करा"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"कॉपी केलेला मजकूर संपादित करा"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"कॉपी केलेली इमेज संपादित करा"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"जवळपासच्या डिव्हाइसवर पाठवा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 131297939d8d..c0ca50533c8b 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokasi"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"rakaman skrin"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Tiada tajuk"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Tunggu sedia"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Tetingkap Pembesaran"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Apl yang tidak diketahui"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Berhenti menghantar"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Peranti tersedia untuk audio output."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cara siaran berfungsi"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Siarkan"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Orang berdekatan anda dengan peranti Bluetooth yang serasi boleh mendengar media yang sedang anda siarkan"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Selesai"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Disalin"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Daripada <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ketepikan penyalinan UI"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Ketepikan teks yang disalin"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit teks yang disalin"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit imej yang disalin"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Hantar ke peranti berdekatan"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 6ae71c411233..2611f9bcd002 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"ကင်မရာ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"တည်နေရာ"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"မိုက်ခရိုဖုန်း"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"စခရင်ရိုက်ကူးမှု"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ခေါင်းစဉ် မရှိပါ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"အသင့်အနေအထား"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ဝင်းဒိုး ချဲ့ခြင်း"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"အမည်မသိ အက်ပ်"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ကာစ် ရပ်ရန်"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"အသံအထွက်အတွက် ရရှိနိုင်သောစက်များ။"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ထုတ်လွှင့်မှုဆောင်ရွက်ပုံ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ထုတ်လွှင့်ခြင်း"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"အနီးရှိတွဲသုံးနိုင်သော ဘလူးတုသ်သုံးစက် အသုံးပြုသူများက သင်ထုတ်လွှင့်နေသော မီဒီယာကို နားဆင်နိုင်သည်"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"ပြီးပြီ"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"ကူးပြီးပါပြီ"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> ထံမှ"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI မိတ္တူမကူးတော့ရန်"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"မိတ္တူကူးထားသောစာသားကို ပယ်ရန်"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"ကူးထားသည့်စာသားကို တည်းဖြတ်ရန်"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"ကူးထားသည့်ပုံကို ပြင်ဆင်ရန်"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"အနီးတစ်ဝိုက်ရှိ စက်များသို့ ပို့ရန်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 7b4e6458791f..49d31101a379 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -320,10 +320,12 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Låst opp med ansiktet. Trykk for å åpne."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Ansiktet er gjenkjent. Trykk for å åpne."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Ansiktet er gjenkjent. Trykk på lås opp-ikon for å fortsette"</string>
- <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
- <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
- <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
- <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
+ <string-array name="udfps_accessibility_touch_hints">
+ <item msgid="1901953991150295169">"Flytt til venstre"</item>
+ <item msgid="5558598599408514296">"Flytt ned"</item>
+ <item msgid="4844142668312841831">"Flytt til høyre"</item>
+ <item msgid="5640521437931460125">"Flytt opp"</item>
+ </string-array>
<string name="keyguard_retry" msgid="886802522584053523">"Sveip opp for å prøve igjen"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås opp for å bruke NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Denne enheten tilhører organisasjonen din"</string>
@@ -699,10 +701,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Varsler"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Batteri"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Skjermdumper"</string>
- <!-- no translation found for notification_channel_instant (7556135423486752680) -->
- <skip />
- <!-- no translation found for notification_channel_setup (7660580986090760350) -->
- <skip />
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Konfigurering"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Lagring"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Hint"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kameraet"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"posisjon"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofonen"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"skjermopptak"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ingen tittel"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ventemodus"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Forstørringsvindu"</string>
@@ -854,7 +855,8 @@
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"For å caste denne økten, åpne appen."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Ukjent app"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stopp castingen"</string>
- <!-- no translation found for media_output_dialog_accessibility_title (4681741064190167888) -->
+ <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Tilgjengelige enheter for lydutgang."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Slik fungerer kringkasting"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Kringkasting"</string>
@@ -947,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Ferdig"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopiert"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Fra <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Lukk kopi-UI"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Lukk kopiert tekst"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Rediger den kopierte teksten"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Rediger det kopierte bildet"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send til en enhet i nærheten"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 8712b48380c6..71533696412a 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"क्यामेरा"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"स्थान"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"माइक्रोफोन"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"स्क्रिन रेकर्डिङ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"शीर्षक छैन"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्ट्यान्डबाई"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"म्याग्निफिकेसन विन्डो"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"अज्ञात एप"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"कास्ट गर्न छाड्नुहोस्"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"अडियो आउटपुटका लागि उपलब्ध डिभाइसहरू।"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"प्रसारण गर्ने सुविधाले कसरी काम गर्छ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"प्रसारण"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"कम्प्याटिबल ब्लुटुथ डिभाइस भएका नजिकैका मान्छेहरू तपाईंले प्रसारण गरिरहनुभएको मिडिया सुन्न सक्छन्"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"सम्पन्न भयो"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"कपी गरियो"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> बाट"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"कपी UI खारेज गर्नुहोस्"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"कपी गरिएको टेक्स्ट हटाउनुहोस्"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"कपी गरिएको टेक्स्ट सम्पादन गर्नुहोस्"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"कपी गरिएको फोटो सम्पादन गर्नुहोस्"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"नजिकैको डिभाइसमा पठाउनुहोस्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index c2a29f189771..09d4db4b814a 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"locatie"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microfoon"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"schermopname"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Geen titel"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stand-by"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vergrotingsvenster"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Onbekende app"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Casten stoppen"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Beschikbare apparaten voor audio-uitvoer."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Hoe uitzenden werkt"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Uitzending"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Mensen bij jou in de buurt met geschikte bluetooth-apparaten kunnen luisteren naar de media die je uitzendt"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Klaar"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Gekopieerd"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Uit <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI voor kopiëren sluiten"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Gekopieerde tekst sluiten"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Gekopieerde tekst bewerken"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Gekopieerde afbeelding bewerken"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Naar apparaat in de buurt sturen"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 6fe0f6932046..0d6253dc3785 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"କ୍ୟାମେରା"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ଲୋକେସନ୍‍"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"ମାଇକ୍ରୋଫୋନ୍"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"ସ୍କ୍ରିନ ରେକର୍ଡିଂ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"କୌଣସି ଶୀର୍ଷକ ନାହିଁ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ଷ୍ଟାଣ୍ଡବାଏ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ୱିଣ୍ଡୋ"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"ଅଜଣା ଆପ"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"କାଷ୍ଟ କରିବା ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ଅଡିଓ ଆଉଟପୁଟ ପାଇଁ ଉପଲବ୍ଧ ଡିଭାଇସଗୁଡ଼ିକ।"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ବ୍ରଡକାଷ୍ଟିଂ କିପରି କାମ କରେ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ବ୍ରଡକାଷ୍ଟ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ଆପଣଙ୍କ ଆଖପାଖର କମ୍ପାଟିବଲ ବ୍ଲୁଟୁଥ ଡିଭାଇସ ଥିବା ଲୋକମାନେ ଆପଣ ବ୍ରଡକାଷ୍ଟ କରୁଥିବା ମିଡିଆ ଶୁଣିପାରିବେ"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"ହୋଇଗଲା"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"କପି କରାଯାଇଛି"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g>ରୁ"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"କପି କରାଯାଇଥିବା UIକୁ ଖାରଜ କରନ୍ତୁ"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"କପି କରାଯାଇଥିବା ଟେକ୍ସଟକୁ ଖାରଜ କରନ୍ତୁ"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"କପି କରାଯାଇଥିବା ଟେକ୍ସଟକୁ ଏଡିଟ କରନ୍ତୁ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"କପି କରାଯାଇଥିବା ଇମେଜକୁ ଏଡିଟ କରନ୍ତୁ"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ନିକଟସ୍ଥ ଡିଭାଇସକୁ ପଠାନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 5f4120267c8d..207a318b7bad 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"ਕੈਮਰਾ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ਟਿਕਾਣਾ"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ਕੋਈ ਸਿਰਲੇਖ ਨਹੀਂ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ਸਟੈਂਡਬਾਈ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ਵੱਡਦਰਸ਼ੀਕਰਨ Window"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"ਅਗਿਆਤ ਐਪ"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ਕਾਸਟ ਕਰਨਾ ਬੰਦ ਕਰੋ"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ਆਡੀਓ ਆਊਟਪੁੱਟ ਲਈ ਉਪਲਬਧ ਡੀਵਾਈਸ।"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ਪ੍ਰਸਾਰਨ ਕਿਵੇਂ ਕੰਮ ਕਰਦਾ ਹੈ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ਪ੍ਰਸਾਰਨ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ਅਨੁਰੂਪ ਬਲੂਟੁੱਥ ਡੀਵਾਈਸਾਂ ਨਾਲ ਨਜ਼ਦੀਕੀ ਲੋਕ ਤੁਹਾਡੇ ਵੱਲੋਂ ਪ੍ਰਸਾਰਨ ਕੀਤੇ ਜਾ ਰਹੇ ਮੀਡੀਆ ਨੂੰ ਸੁਣ ਸਕਦੇ ਹਨ"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"ਹੋ ਗਿਆ"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"ਕਾਪੀ ਕੀਤੀ ਗਈ"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> ਤੋਂ"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"ਕਾਪੀ ਕੀਤੇ UI ਨੂੰ ਖਾਰਜ ਕਰੋ"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"ਕਾਪੀ ਕੀਤੀ ਲਿਖਤ ਨੂੰ ਖਾਰਜ ਕਰੋ"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"ਕਾਪੀ ਕੀਤੀ ਲਿਖਤ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"ਕਾਪੀ ਕੀਤੇ ਗਏ ਚਿੱਤਰ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸ \'ਤੇ ਭੇਜੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index ce225f165ddd..c06b66347bf7 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -324,10 +324,12 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Odblokowano rozpoznawaniem twarzy. Naciśnij, by otworzyć."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Twarz rozpoznana. Naciśnij, by otworzyć."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Twarz rozpoznana. Aby otworzyć, kliknij ikonę odblokowywania."</string>
- <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
- <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
- <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
- <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
+ <string-array name="udfps_accessibility_touch_hints">
+ <item msgid="1901953991150295169">"Przenieś w lewo"</item>
+ <item msgid="5558598599408514296">"Przenieś w dół"</item>
+ <item msgid="4844142668312841831">"Przenieś w prawo"</item>
+ <item msgid="5640521437931460125">"Przenieś w górę"</item>
+ </string-array>
<string name="keyguard_retry" msgid="886802522584053523">"Przesuń w górę, by spróbować ponownie"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Odblokuj, by użyć komunikacji NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"To urządzenie należy do Twojej organizacji"</string>
@@ -709,10 +711,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Alerty"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Bateria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Zrzuty ekranu"</string>
- <!-- no translation found for notification_channel_instant (7556135423486752680) -->
- <skip />
- <!-- no translation found for notification_channel_setup (7660580986090760350) -->
- <skip />
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Aplikacje błyskawiczne"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Konfiguracja"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Pamięć wewnętrzna"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Wskazówki"</string>
<string name="instant_apps" msgid="8337185853050247304">"Aplikacje błyskawiczne"</string>
@@ -760,6 +760,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"aparat"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokalizacja"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"nagrywanie ekranu"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez tytułu"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Tryb gotowości"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Okno powiększenia"</string>
@@ -866,7 +867,8 @@
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Aby przesłać tę sesję, otwórz aplikację."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nieznana aplikacja"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zatrzymaj przesyłanie"</string>
- <!-- no translation found for media_output_dialog_accessibility_title (4681741064190167888) -->
+ <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dostępne urządzenia do odtwarzania dźwięku."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Jak działa transmitowanie"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmisja"</string>
@@ -961,7 +963,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Gotowe"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Skopiowano"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Od: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Zamknij UI kopiowania"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Odrzuć skopiowany tekst"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edytuj skopiowany tekst"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edytuj skopiowany obraz"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Wyślij na urządzenie w pobliżu"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 8c0591161c4b..7945912fb0b9 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"câmera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"localização"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microfone"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"gravação de tela"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sem título"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Em espera"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App desconhecido"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Parar transmissão"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositivos disponíveis para saída de áudio."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funciona a transmissão"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmitir"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"As pessoas próximas a você com dispositivos Bluetooth compatíveis podem ouvir a mídia que você está transmitindo"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Concluído"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiado"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Do app <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dispensar cópia da IU"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Dispensar texto copiado"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imagem copiada"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar para dispositivo próximo"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 7128bbf2816a..eab44136e7c5 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"câmara"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"localização"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microfone"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"gravação de ecrã"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sem título"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Modo de espera"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App desconhecida"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Parar transmissão"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositivos disponíveis para a saída de áudio."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funciona a transmissão"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmissão"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"As pessoas próximas de si com dispositivos Bluetooth compatíveis podem ouvir o conteúdo multimédia que está a transmitir"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Concluir"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiado"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Da app <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignorar cópia de IU"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Ignorar texto copiado"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imagem copiada"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar para dispositivo próximo"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 8c0591161c4b..7945912fb0b9 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"câmera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"localização"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microfone"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"gravação de tela"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sem título"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Em espera"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App desconhecido"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Parar transmissão"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositivos disponíveis para saída de áudio."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funciona a transmissão"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmitir"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"As pessoas próximas a você com dispositivos Bluetooth compatíveis podem ouvir a mídia que você está transmitindo"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Concluído"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiado"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Do app <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dispensar cópia da IU"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Dispensar texto copiado"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imagem copiada"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar para dispositivo próximo"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index ca47e05de095..3715b8e70212 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -755,6 +755,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"cameră foto"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"locație"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microfon"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"înregistrare de ecran"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Fără titlu"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Fereastra de mărire"</string>
@@ -861,6 +862,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplicație necunoscută"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Nu mai proiectați"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispozitive disponibile pentru ieșire audio."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cum funcționează transmisia"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmiteți"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Persoanele din apropiere cu dispozitive Bluetooth compatibile pot asculta conținutul pe care îl transmiteți"</string>
@@ -953,7 +956,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Gata"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"S-a copiat"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Din <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Închideți copierea interfeței de utilizare"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Închideți textul copiat"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editați textul copiat"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editați imaginea copiată"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Trimiteți către un dispozitiv din apropiere"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 297d81036e07..e444d2ba67d3 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -760,6 +760,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"местоположение"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"запись экрана"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без названия"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Переход в режим ожидания"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Окно увеличения"</string>
@@ -867,6 +868,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Неизвестное приложение"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Остановить трансляцию"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Доступные устройства для вывода звука."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Как работают трансляции"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Трансляция"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Находящиеся рядом с вами люди с совместимыми устройствами Bluetooth могут слушать медиафайлы, которые вы транслируете."</string>
@@ -933,7 +936,7 @@
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Нет других доступных сетей"</string>
<string name="all_network_unavailable" msgid="4112774339909373349">"Нет доступных сетей"</string>
<string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
- <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Выберите сеть, чтобы подключиться"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Чтобы подключиться к сети, нажмите на ее название"</string>
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Разблокируйте, чтобы посмотреть сети Wi-Fi."</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Поиск сетей…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не удалось подключиться к сети"</string>
@@ -960,7 +963,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Готово"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Скопировано."</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Из приложения \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Закрыть меню копирования"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Удалить скопированный текст"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Изменить скопированный текст"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Изменить скопированное изображение"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Отправить на устройство поблизости"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 60f50ca5d01c..12614b075ad4 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"කැමරාව"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ස්ථානය"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"මයික්‍රෝෆෝනය"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"තිර පටිගත කිරීම"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"මාතෘකාවක් නැත"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"පොරොත්තු"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"විශාලන කවුළුව"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"නොදන්නා යෙදුම"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"විකාශය නවතන්න"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ශ්‍රව්‍ය ප්‍රතිදානය සඳහා තිබෙන උපාංග."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"විකාශනය ක්‍රියා කරන ආකාරය"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"විකාශනය"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ගැළපෙන බ්ලූටූත් උපාංග සහිත ඔබ අවට සිටින පුද්ගලයින්ට ඔබ විකාශනය කරන මාධ්‍යයට සවන් දිය හැකිය"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"නිමයි"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"පිටපත් කරන ලදි"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> සිට"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dismiss copy UI"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"පිටපත් කළ පෙළ අස් කරන්න"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"පිටපත් කළ පෙළ සංස්කරණය කරන්න"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"පිටපත් කළ රූපය සංස්කරණය කරන්න"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"අවට උපාංගය වෙත යවන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index ddaebb01857a..2652e57e562a 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -760,6 +760,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparát"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"poloha"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofón"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"nahrávanie obrazovky"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez názvu"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Pohotovostný režim"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Okno priblíženia"</string>
@@ -867,6 +868,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Neznáma aplikácia"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zastaviť prenos"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dostupné zariadenia pre zvukový výstup."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Ako vysielanie funguje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Vysielanie"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Ľudia v okolí s kompatibilnými zariadeniami s rozhraním Bluetooth si môžu vypočuť médiá, ktoré vysielate"</string>
@@ -960,7 +963,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Hotovo"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Skopírované"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Z aplikácie <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Používateľské rozhranie zahodenia kópie"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Zrušiť skopírovaný text"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Upraviť skopírovaný text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Upraviť skopírovaný obrázok"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Odoslať do zariadenia v okolí"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index c29674bc29cf..ab24cfb36440 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -760,6 +760,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparat"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokacijo"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"snemanje zaslona"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Brez naslova"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje pripravljenosti"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Povečevalno okno"</string>
@@ -867,6 +868,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Neznana aplikacija"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Ustavi predvajanje"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Razpoložljive naprave za zvočni izhod"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako deluje oddajanje"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Oddajanje"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Osebe v bližini z združljivo napravo Bluetooth lahko poslušajo predstavnost, ki jo oddajate."</string>
@@ -960,7 +963,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Končano"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopirano"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Iz aplikacije <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Opusti kopiranje uporabniškega vmesnika"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Opusti kopirano besedilo"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Uredi kopirano besedilo"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Uredi kopirano sliko"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Pošlji v napravo v bližini"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 0bae296a9a08..03f89fbd9f48 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamerën"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"vendndodhjen"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofonin"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"regjistrim i ekranit"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Pa titull"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Në gatishmëri"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Dritarja e zmadhimit"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplikacion i panjohur"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Ndalo transmetimin"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Pajisjet që ofrohen për daljen e audios."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Si funksionon transmetimi"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Transmetimi"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Personat në afërsi me ty me pajisje të përputhshme me Bluetooth mund të dëgjojnë median që ti po transmeton"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"U krye"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"U kopjua"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Nga <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Hiq kopjen e ndërfaqes së përdoruesit"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Hiq tekstin e kopjuar"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Modifiko tekstin e kopjuar"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Modifiko imazhin e kopjuar"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Dërgo te pajisja në afërsi"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 3f86e9e08e9d..fcb2d807e687 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -755,6 +755,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"камеру"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"локацију"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"снимање екрана"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без наслова"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Стање приправности"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Прозор за увећање"</string>
@@ -861,6 +862,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Непозната апликација"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Заустави пребацивање"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Доступни уређаји за аудио излаз."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Како функционише емитовање"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Емитовање"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Људи у близини са компатибилним Bluetooth уређајима могу да слушају медијски садржај који емитујете"</string>
@@ -953,7 +956,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Готово"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Копирано је"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Од: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Одбаци копирање корисничког интерфејса"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Одбаци копирани текст"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Измените копирани текст"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Измените копирану слику"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Пошаљи на уређај у близини"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 2008e99296ac..409905a315ff 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"plats"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"skärminspelning"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ingen titel"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Viloläge"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Förstoringsfönster"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Okänd app"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Sluta casta"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Enheter som är tillgängliga för ljudutdata."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Så fungerar utsändning"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Utsändning"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Personer i närheten med kompatibla Bluetooth-enheter kan lyssna på medieinnehåll som du sänder ut"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Klar"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopierades"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Från <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Stäng användargränssnittet för kopiering"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Ta bort kopierad text"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Redigera kopierad text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Redigera kopierad bild"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Skicka till enhet i närheten"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index a413c360bd25..885e9bdf816c 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"mahali"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"maikrofoni"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"kurekodi skrini"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Wimbo hauna jina"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Hali tuli"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Dirisha la Ukuzaji"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Programu isiyojulikana"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Acha kutuma"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Vifaa vya kutoa sauti vilivyopo"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Jinsi utangazaji unavyofanya kazi"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Tangaza"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Watu walio karibu nawe wenye vifaa oanifu vya Bluetooth wanaweza kusikiliza maudhui unayoyatangaza"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Imemaliza"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Imenakiliwa"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Kutoka <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ondoa kiolesura cha nakala"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Ondoa maandishi yaliyonakiliwa"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Badilisha maandishi yaliyonakiliwa"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Badilisha picha iliyonakiliwa"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Tuma kwenye kifaa kilicho karibu"</string>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 6c42073b8805..d638c9d5742e 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -47,6 +47,8 @@
<dimen name="lockscreen_shade_max_over_scroll_amount">32dp</dimen>
+ <dimen name="status_view_margin_horizontal">8dp</dimen>
+
<!-- Distance that the full shade transition takes in order to complete by tapping on a button
like "expand". -->
<dimen name="lockscreen_shade_transition_by_tap_distance">200dp</dimen>
diff --git a/packages/SystemUI/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
index f45f106d391d..868c003d99a5 100644
--- a/packages/SystemUI/res/values-sw720dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
@@ -25,6 +25,8 @@
<dimen name="status_bar_header_height_keyguard">56dp</dimen>
+ <dimen name="status_view_margin_horizontal">24dp</dimen>
+
<dimen name="qs_media_session_height_expanded">251dp</dimen>
<dimen name="qs_content_horizontal_padding">40dp</dimen>
<dimen name="qs_horizontal_margin">40dp</dimen>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 4cd090561e14..7196f5da3fc0 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"கேமரா"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"இருப்பிடம்"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"மைக்ரோஃபோன்"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"ஸ்கிரீன் ரெக்கார்டிங்"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"தலைப்பு இல்லை"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"இயக்க நேரம்"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"பெரிதாக்கல் சாளரம்"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"அறியப்படாத ஆப்ஸ்"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"அலைபரப்புவதை நிறுத்து"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ஆடியோ அவுட்புட்டுக்குக் கிடைக்கும் சாதனங்கள்."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"பிராட்காஸ்ட் எவ்வாறு செயல்படுகிறது?"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"பிராட்காஸ்ட்"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"நீங்கள் பிராட்காஸ்ட் செய்யும் மீடியாவை அருகிலுள்ளவர்கள் இணக்கமான புளூடூத் சாதனங்கள் மூலம் கேட்கலாம்"</string>
@@ -921,7 +924,7 @@
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"வேறு நெட்வொர்க்குகள் எதுவும் கிடைக்கவில்லை"</string>
<string name="all_network_unavailable" msgid="4112774339909373349">"நெட்வொர்க்குகள் எதுவும் கிடைக்கவில்லை"</string>
<string name="turn_on_wifi" msgid="1308379840799281023">"வைஃபை"</string>
- <string name="tap_a_network_to_connect" msgid="1565073330852369558">"இணையத்துடன் இணைய நெட்வொர்க்கைத் தட்டுங்கள்"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"இணைய நெட்வொர்க்கைத் தட்டுங்கள்"</string>
<string name="unlock_to_view_networks" msgid="5072880496312015676">"நெட்வொர்க்குகளைப் பார்க்க அன்லாக் செய்யுங்கள்"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"நெட்வொர்க்குகளைத் தேடுகிறது…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"நெட்வொர்க்குடன் இணைக்க முடியவில்லை"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"முடிந்தது"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"நகலெடுக்கப்பட்டது"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> ஆப்ஸிலிருந்து"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"கிளிப்போர்டு மேலடுக்கை மூடுக"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"நகலெடுக்கப்பட்ட வார்த்தைகளை மூடுக"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"நகலெடுத்த வார்த்தைகளைத் திருத்து"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"நகலெடுத்த படத்தைத் திருத்து"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"அருகிலுள்ள சாதனத்திற்கு அனுப்பு"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index afba45405e3c..cac9cfdf46b9 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"కెమెరా"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"లొకేషన్"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"మైక్రోఫోన్"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"స్క్రీన్ రికార్డింగ్"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"శీర్షిక లేదు"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"స్టాండ్‌బై"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"మాగ్నిఫికేషన్ విండో"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"తెలియని యాప్"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ప్రసారాన్ని ఆపివేయండి"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ఆడియో అవుట్‌పుట్ కోసం అందుబాటులో ఉన్న పరికరాలు."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ప్రసారం కావడం అనేది ఎలా పని చేస్తుంది"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ప్రసారం"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"మీకు సమీపంలో ఉన్న వ్యక్తులు అనుకూలత ఉన్న బ్లూటూత్ పరికరాలతో మీరు ప్రసారం చేస్తున్న మీడియాను వినగలరు"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"పూర్తయింది"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"కాపీ అయింది"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> నుండి"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"కాపీ UIని విస్మరించండి"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"కాపీ చేసిన టెక్స్ట్‌ను విస్మరించండి"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"కాపీ చేసిన టెక్స్ట్‌ను ఎడిట్ చేయండి"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"కాపీ చేసిన ఇమేజ్‌లను ఎడిట్ చేయండి"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"సమీపంలోని పరికరానికి పంపండి"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 51cad22508d1..73a7350e7782 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"กล้องถ่ายรูป"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ตำแหน่ง"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"ไมโครโฟน"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"การบันทึกหน้าจอ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ไม่มีชื่อ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"สแตนด์บาย"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"หน้าต่างการขยาย"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"แอปที่ไม่รู้จัก"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"หยุดแคสต์"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"อุปกรณ์ที่พร้อมใช้งานสำหรับเอาต์พุตเสียง"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"วิธีการทำงานของการออกอากาศ"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"ประกาศ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ผู้ที่อยู่ใกล้คุณและมีอุปกรณ์บลูทูธที่รองรับสามารถรับฟังสื่อที่คุณกำลังออกอากาศได้"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"เสร็จ"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"คัดลอกแล้ว"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"จาก <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"ปิด UI การคัดลอก"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"ปิดข้อความที่คัดลอก"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"แก้ไขข้อความที่คัดลอก"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"แก้ไขรูปภาพที่คัดลอก"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ส่งไปยังอุปกรณ์ที่อยู่ใกล้เคียง"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index bd1cfdbc6848..1d5c0883ee86 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokasyon"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikropono"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"pag-record ng screen"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Walang pamagat"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Naka-standby"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Window ng Pag-magnify"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Hindi kilalang app"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Ihinto ang pag-cast"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Mga available na device para sa audio output."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Paano gumagana ang pag-broadcast"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Makakapakinig ang mga taong malapit sa iyo na may mga compatible na Bluetooth device sa media na bino-broadcast mo"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Tapos na"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Nakopya"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Mula sa <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"I-dismiss ang UI ng pagkopya"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"I-dismiss ang nakopyang text"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"I-edit ang kinopyang text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"I-edit ang kinopyang larawan"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Ipadala sa kalapit na device"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 69cdbf26156e..dcdb604a374e 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"konum"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"ekran kaydı"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Başlıksız"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Beklemeye alınıyor"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Büyütme Penceresi"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Bilinmeyen uygulama"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Yayını durdur"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Ses çıkışı için kullanılabilir cihazlar."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Yayınlamanın işleyiş şekli"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Anons"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Yakınınızda ve uyumlu Bluetooth cihazları olan kişiler yayınladığınız medya içeriğini dinleyebilir"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Bitti"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopyalandı"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> uygulamasından"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Kopyalanan kullanıcı arayüzünü kapat"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Kopyalanan metni kapat"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Kopyalanan metni düzenle"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Kopyalanan resmi düzenle"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Yakındaki cihaza gönder"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 8b9c65843a45..a86917069734 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -324,10 +324,12 @@
<string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Розблоковано (фейсконтроль). Натисніть, щоб відкрити."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Обличчя розпізнано. Натисніть, щоб відкрити."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Обличчя розпізнано. Натисніть значок розблокування."</string>
- <!-- no translation found for udfps_accessibility_touch_hints:0 (1901953991150295169) -->
- <!-- no translation found for udfps_accessibility_touch_hints:1 (5558598599408514296) -->
- <!-- no translation found for udfps_accessibility_touch_hints:2 (4844142668312841831) -->
- <!-- no translation found for udfps_accessibility_touch_hints:3 (5640521437931460125) -->
+ <string-array name="udfps_accessibility_touch_hints">
+ <item msgid="1901953991150295169">"Перемістіть палець ліворуч"</item>
+ <item msgid="5558598599408514296">"Перемістіть палець униз"</item>
+ <item msgid="4844142668312841831">"Перемістіть палець праворуч"</item>
+ <item msgid="5640521437931460125">"Перемістіть палець угору"</item>
+ </string-array>
<string name="keyguard_retry" msgid="886802522584053523">"Проведіть пальцем угору, щоб повторити спробу"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Розблокуйте екран, щоб скористатись NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Цей пристрій належить вашій організації"</string>
@@ -709,10 +711,8 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Сповіщення"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Акумулятор"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Знімки екрана"</string>
- <!-- no translation found for notification_channel_instant (7556135423486752680) -->
- <skip />
- <!-- no translation found for notification_channel_setup (7660580986090760350) -->
- <skip />
+ <string name="notification_channel_instant" msgid="7556135423486752680">"Додатки з миттєвим запуском"</string>
+ <string name="notification_channel_setup" msgid="7660580986090760350">"Налаштування"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Пам’ять"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Поради"</string>
<string name="instant_apps" msgid="8337185853050247304">"Додатки з миттєвим запуском"</string>
@@ -760,6 +760,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"місце"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"мікрофон"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"запис відео з екрана"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без назви"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Режим очікування"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Вікно збільшення"</string>
@@ -866,7 +867,8 @@
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Щоб транслювати цей сеанс, відкрийте додаток."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Невідомий додаток"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Припинити трансляцію"</string>
- <!-- no translation found for media_output_dialog_accessibility_title (4681741064190167888) -->
+ <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Доступні пристрої для відтворення звуку."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
<skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Як працює трансляція"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Трансляція"</string>
@@ -961,7 +963,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Готово"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Скопійовано"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"З додатка <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Закрити вікно копіювання"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Закрити буфер обміну зі скопійованим текстом"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Редагувати скопійований текст"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Редагувати скопійоване зображення"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Надіслати на пристрій поблизу"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 874314ac997d..717dafbd8402 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"کیمرا"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"مقام"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"مائیکروفون"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"اسکرین ریکارڈنگ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"کوئی عنوان نہیں ہے"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"اسٹینڈ بائی"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"میگنیفکیشن ونڈو"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"نامعلوم ایپ"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"کاسٹ کرنا بند کریں"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"آڈیو آؤٹ پٹ کے لیے دستیاب آلات۔"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"براڈکاسٹنگ کیسے کام کرتا ہے"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"براڈکاسٹ"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"موافق بلوٹوتھ آلات کے ساتھ آپ کے قریبی لوگ آپ کے نشر کردہ میڈیا کو سن سکتے ہیں"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"ہو گیا"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"کاپی کر دیا گیا ہے"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"‫<xliff:g id="APPNAME">%1$s</xliff:g> سے"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"‏کاپی شدہ UI کو برخاست کریں"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"کاپی کردہ ٹیکسٹ برخاست کریں"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"کاپی کردہ ٹیکسٹ میں ترمیم کریں"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"کاپی کردہ تصویر میں ترمیم کریں"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"قریبی آلے کو بھیجیں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 95b91574a399..65602d24661c 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"joylashuv"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"ekranni yozuvi"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nomsiz"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Kutib turing"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Kattalashtirish oynasi"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Notanish ilova"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Toʻxtatish"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Audio chiqish uchun mavjud qurilmalar."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Translatsiya qanday ishlaydi"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Translatsiya"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Atrofingizdagi mos Bluetooth qurilmasiga ega foydalanuvchilar siz translatsiya qilayotgan mediani tinglay olishadi"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Tayyor"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Nusxa olindi"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Manba: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI nusxasini bekor qilish"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Nusxalangan matnni yopish"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Nusxa olingan matnni tahrirlash"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Nusxa olingan rasmni tahrirlash"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Yaqin-atrofdagi qurilmaga yuborish"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 8ca6ee486fd9..1fda576f1e4c 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"máy ảnh"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"vị trí"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"micrô"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"ghi màn hình"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Không có tiêu đề"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Chế độ chờ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Cửa sổ phóng to"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Ứng dụng không xác định"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Dừng truyền"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Các thiết bị có sẵn để xuất âm thanh."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cách tính năng truyền hoạt động"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Truyền"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Những người ở gần có thiết bị Bluetooth tương thích có thể nghe nội dung nghe nhìn bạn đang truyền"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Xong"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Đã sao chép"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Từ <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Đóng giao diện người dùng sao chép"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Loại bỏ văn bản đã sao chép"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Chỉnh sửa văn bản đã sao chép"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Chỉnh sửa hình ảnh đã sao chép"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Gửi đến thiết bị ở gần"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 3021eb259d2f..a073abf586fe 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"相机"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"位置信息"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"麦克风"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"屏幕录制"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"无标题"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待机"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"放大窗口"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"未知应用"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"停止投射"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"音频输出的可用设备。"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"广播的运作方式"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"广播"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"附近使用兼容蓝牙设备的用户可以收听您广播的媒体内容"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"完成"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"已复制"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"来自<xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"关闭复制界面"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"忽略复制的文字"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"修改所复制的文字"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"编辑所复制的图片"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"发送到附近的设备"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 72212e339897..edf79fe96138 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"相機"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"位置"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"麥克風"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"錄製螢幕畫面"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"無標題"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待機"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"放大視窗"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"不明應用程式"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"停止投放"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"可用作音訊輸出的裝置"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"廣播運作方式"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"廣播"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"附近有兼容藍牙裝置的人可收聽您正在廣播的媒體內容"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"完成"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"已複製"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"來自「<xliff:g id="APPNAME">%1$s</xliff:g>」"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"關閉剪貼簿使用者介面"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"關閉剪貼簿"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"編輯已複製的文字"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"編輯已複製的圖片"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"傳送至附近的裝置"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index baf6f6d54ac0..5282af465fb9 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"相機"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"位置"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"麥克風"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"錄製螢幕畫面"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"無標題"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待機"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"放大視窗"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"不明的應用程式"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"停止投放"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"可用於輸出音訊的裝置。"</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"廣播功能的運作方式"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"廣播"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"如果附近的人有相容的藍牙裝置,就可以聽到你正在廣播的媒體內容"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"完成"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"已複製"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"來自「<xliff:g id="APPNAME">%1$s</xliff:g>」"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"關閉剪貼簿 UI"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"關閉剪貼簿"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"編輯複製的文字"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"編輯複製的圖片"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"傳送到鄰近裝置"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 8ad5a459c9b0..a6407928709f 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -750,6 +750,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"ikhamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"indawo"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"imakrofoni"</string>
+ <string name="privacy_type_media_projection" msgid="8136723828804251547">"ukurekhoda isikrini"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Asikho isihloko"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ilindile"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Iwindi Lesikhulisi"</string>
@@ -855,6 +856,8 @@
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"I-app engaziwa"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Misa ukusakaza"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Amadivayisi atholakalayo okukhipha umsindo."</string>
+ <!-- no translation found for media_output_dialog_accessibility_seekbar (5332843993805568978) -->
+ <skip />
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Indlela ukusakaza okusebenza ngayo"</string>
<string name="media_output_broadcast" msgid="3555580945878071543">"Sakaza"</string>
<string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Abantu abaseduze nawe abanamadivayisi e-Bluetooth ahambisanayo bangalalela imidiya oyisakazayo"</string>
@@ -946,7 +949,7 @@
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Kwenziwe"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Ikopishiwe"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Kusukela ku-<xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="clipboard_dismiss_description" msgid="7544573092766945657">"Chitha ukukopisha i-UI"</string>
+ <string name="clipboard_dismiss_description" msgid="3335990369850165486">"Chitha umbhalo okopishiwe"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Hlela umbhalo okopishiwe"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Hlela umfanekiso okopishiwe"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Thumela kudivayisi eseduze"</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index bfd76c5e29f9..0b8e1dd45e96 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -31,7 +31,7 @@
<!-- dimensions for the navigation bar handle -->
<dimen name="navigation_handle_radius">2dp</dimen>
- <dimen name="navigation_handle_bottom">8dp</dimen>
+ <dimen name="navigation_handle_bottom">10dp</dimen>
<dimen name="navigation_handle_sample_horizontal_margin">10dp</dimen>
<dimen name="navigation_home_handle_width">108dp</dimen>
@@ -44,7 +44,7 @@
<!-- The threshold to drag to trigger the edge action -->
<dimen name="navigation_edge_action_drag_threshold">16dp</dimen>
<!-- The threshold to progress back animation for edge swipe -->
- <dimen name="navigation_edge_action_progress_threshold">400dp</dimen>
+ <dimen name="navigation_edge_action_progress_threshold">412dp</dimen>
<!-- The minimum display position of the arrow on the screen -->
<dimen name="navigation_edge_arrow_min_y">64dp</dimen>
<!-- The amount by which the arrow is shifted to avoid the finger-->
@@ -80,13 +80,11 @@
<dimen name="navigation_edge_active_arrow_length">8dp</dimen>
<dimen name="navigation_edge_active_arrow_height">9dp</dimen>
- <!-- stretch @412 dp -->
- <dimen name="navigation_edge_stretch_threshold">412dp</dimen>
<dimen name="navigation_edge_stretch_margin">18dp</dimen>
<dimen name="navigation_edge_stretch_background_width">74dp</dimen>
<dimen name="navigation_edge_stretch_background_height">60dp</dimen>
- <dimen name="navigation_edge_stretch_left_corners">30dp</dimen>
- <dimen name="navigation_edge_stretch_right_corners">30dp</dimen>
+ <dimen name="navigation_edge_stretch_edge_corners">30dp</dimen>
+ <dimen name="navigation_edge_stretch_far_corners">30dp</dimen>
<dimen name="navigation_edge_stretched_arrow_length">7dp</dimen>
<dimen name="navigation_edge_stretched_arrow_height">10dp</dimen>
@@ -495,7 +493,7 @@
<dimen name="navigation_key_padding">0dp</dimen>
<!-- Floating rotation button -->
- <dimen name="floating_rotation_button_diameter">40dp</dimen>
+ <dimen name="floating_rotation_button_diameter">52dp</dimen>
<dimen name="floating_rotation_button_min_margin">20dp</dimen>
<dimen name="floating_rotation_button_taskbar_left_margin">20dp</dimen>
<dimen name="floating_rotation_button_taskbar_bottom_margin">10dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 7f8e28ac7be4..6cd47d24db4e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -505,10 +505,10 @@
<string name="notification_group_overflow_indicator">+ <xliff:g id="number" example="3">%s</xliff:g></string>
<!-- Content description describing how many more notifications are in a group [CHAR LIMIT=NONE] -->
- <plurals name="notification_group_overflow_description">
- <item quantity="one"><xliff:g id="number" example="1">%s</xliff:g> more notification inside.</item>
- <item quantity="other"><xliff:g id="number" example="3">%s</xliff:g> more notifications inside.</item>
- </plurals>
+ <string name="notification_group_overflow_description">{count, plural,
+ =1 {# more notification inside.}
+ other {# more notifications inside.}
+ }</string>
<!-- Format to use to summarize a message from a contact in a single line of text. For example: "Julia: How's it going?". [CHAR LIMIT=NONE] -->
@@ -654,10 +654,10 @@
the user why they can't toggle the hotspot tile. [CHAR LIMIT=20] -->
<string name="quick_settings_hotspot_secondary_label_data_saver_enabled">Data Saver is on</string>
<!-- QuickSettings: Hotspot: Secondary label for how many devices are connected to the hotspot [CHAR LIMIT=NONE] -->
- <plurals name="quick_settings_hotspot_secondary_label_num_devices">
- <item quantity="one">%d device</item>
- <item quantity="other">%d devices</item>
- </plurals>
+ <string name="quick_settings_hotspot_secondary_label_num_devices">{count, plural,
+ =1 {# device}
+ other {# devices}
+ }</string>
<!-- QuickSettings: Notifications [CHAR LIMIT=NONE] -->
<!-- QuickSettings: Flashlight [CHAR LIMIT=NONE] -->
<string name="quick_settings_flashlight_label">Flashlight</string>
@@ -928,10 +928,10 @@
<string name="user_limit_reached_title">User limit reached</string>
<!-- Message that tells people what's the maximum number of uses allowed on the device. [CHAR_LIMIT=NONE]-->
- <plurals name="user_limit_reached_message">
- <item quantity="one">Only one user can be created.</item>
- <item quantity="other">You can add up to <xliff:g id="count" example="3">%d</xliff:g> users.</item>
- </plurals>
+ <string name="user_limit_reached_message">{count, plural,
+ =1 {Only one user can be created.}
+ other {You can add up to # users.}
+ }</string>
<!-- Title of the confirmation dialog for deleting a user [CHAR LIMIT=NONE] -->
<string name="user_remove_user_title">Remove user?</string>
@@ -1486,20 +1486,20 @@
<!-- Notification: Snooze panel: message indicating how long the notification was snoozed for. [CHAR LIMIT=100]-->
<string name="snoozed_for_time">Snoozed for <xliff:g id="time_amount" example="15 minutes">%1$s</xliff:g></string>
- <!-- Notification:Snooze panel: Snooze options for hours -->
- <plurals name="snoozeHourOptions">
- <item quantity="one">%d hour</item>
- <item quantity="two">%d hours</item>
- <item quantity="few">%d hours</item>
- <item quantity="other">%d hours</item>
- </plurals>
-
- <!-- Notification: Snooze panel: Snooze options for minutes -->
- <plurals name="snoozeMinuteOptions">
- <item quantity="one">%d minute</item>
- <item quantity="few">%d minutes</item>
- <item quantity="other">%d minutes</item>
- </plurals>
+ <!-- Notification:Snooze panel: Snooze options for hours [CHAR LIMIT=NONE]-->
+ <string name="snoozeHourOptions">{count, plural,
+ =1 {# hour}
+ =2 {# hours}
+ few {# hours}
+ other {# hours}
+ }</string>
+
+ <!-- Notification: Snooze panel: Snooze options for minutes [CHAR LIMIT=NONE]-->
+ <string name="snoozeMinuteOptions">{count, plural,
+ =1 {# minute}
+ few {# minutes}
+ other {# minutes}
+ }</string>
<!-- Summary of battery saver not available [CHAR LIMIT=NONE] -->
@@ -2074,6 +2074,9 @@
<!-- Text for microphone app op [CHAR LIMIT=20]-->
<string name="privacy_type_microphone">microphone</string>
+ <!-- Text for media projection privacy type [CHAR LIMIT=20]-->
+ <string name="privacy_type_media_projection">screen recording</string>
+
<!-- What to show on the ambient display player when song doesn't have a title. [CHAR LIMIT=20] -->
<string name="music_controls_no_title">No title</string>
@@ -2133,10 +2136,10 @@
<!-- Controls management providers screen title [CHAR LIMIT=60]-->
<string name="controls_providers_title">Choose app to add controls</string>
<!-- Number of favorites for controls management screen [CHAR LIMIT=NONE]-->
- <plurals name="controls_number_of_favorites">
- <item quantity="one"><xliff:g id="number" example="1">%s</xliff:g> control added.</item>
- <item quantity="other"><xliff:g id="number" example="3">%s</xliff:g> controls added.</item>
- </plurals>
+ <string name="controls_number_of_favorites">{count, plural,
+ =1 {# control added.}
+ other {# controls added.}
+ }</string>
<!-- Removed control in management screen [CHAR LIMIT=20] -->
<string name="controls_removed">Removed</string>
@@ -2309,6 +2312,8 @@
<string name="media_output_dialog_button_stop_casting">Stop casting</string>
<!-- Accessibility text describing purpose of media output dialog. [CHAR LIMIT=NONE] -->
<string name="media_output_dialog_accessibility_title">Available devices for audio output.</string>
+ <!-- Accessibility text describing purpose of seekbar in media output dialog. [CHAR LIMIT=NONE] -->
+ <string name="media_output_dialog_accessibility_seekbar">Volume</string>
<!-- Media Output Broadcast Dialog -->
<!-- Title for Broadcast First Notify Dialog [CHAR LIMIT=60] -->
@@ -2490,17 +2495,17 @@
<string name="qs_user_switch_dialog_title">Select user</string>
<!-- Label for the entry point to open the dialog which shows currently running applications [CHAR LIMIT=NONE]-->
- <plurals name="fgs_manager_footer_label">
- <item quantity="one"><xliff:g id="count" example="1">%s</xliff:g> app is active</item>
- <item quantity="other"><xliff:g id="count" example="2">%s</xliff:g> apps are active</item>
- </plurals>
+ <string name="fgs_manager_footer_label">{count, plural,
+ =1 {# app is active}
+ other {# apps are active}
+ }</string>
<!-- Content description for a dot indicator in the running application indicating that there
is new information [CHAR LIMIT=NONE] -->
<string name="fgs_dot_content_description">New information</string>
<!-- Title for dialog listing applications currently running [CHAR LIMIT=NONE]-->
<string name="fgs_manager_dialog_title">Active apps</string>
<!-- Detailed message for dialog listing applications currently running [CHAR LIMIT=NONE]-->
- <string name="fgs_manager_dialog_message">Even if you\u2019re not using these apps, they\u2019re still active and might affect battery life</string>
+ <string name="fgs_manager_dialog_message">These apps are active and running, even when you\u2019re not using them. This improves their functionality, but it may also affect battery life.</string>
<!-- Label of the button to stop an app from running [CHAR LIMIT=12]-->
<string name="fgs_manager_app_item_stop_button_label">Stop</string>
<!-- Label of the button to stop an app from running but the app is already stopped and the button is disabled [CHAR LIMIT=12]-->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
index 01f417f147d7..b29dc835a6f4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
@@ -20,6 +20,7 @@ import static android.content.pm.PackageManager.FEATURE_PC;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.internal.view.RotationPolicy.NATURAL_ROTATION;
+import static com.android.systemui.shared.system.QuickStepContract.isGesturalMode;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -97,6 +98,7 @@ public class RotationButtonController {
@SuppressLint("InlinedApi")
private @WindowInsetsController.Behavior
int mBehavior = WindowInsetsController.BEHAVIOR_DEFAULT;
+ private int mNavBarMode;
private boolean mSkipOverrideUserLockPrefsOnce;
private final int mLightIconColor;
private final int mDarkIconColor;
@@ -397,6 +399,10 @@ public class RotationButtonController {
if (rotateSuggestionsDisabled) onRotationSuggestionsDisabled();
}
+ public void onNavigationModeChanged(int mode) {
+ mNavBarMode = mode;
+ }
+
public void onBehaviorChanged(int displayId, @WindowInsetsController.Behavior int behavior) {
if (DEFAULT_DISPLAY != displayId) {
return;
@@ -433,7 +439,8 @@ public class RotationButtonController {
*/
@SuppressLint("InlinedApi")
private boolean canShowRotationButton() {
- return mIsNavigationBarShowing || mBehavior == WindowInsetsController.BEHAVIOR_DEFAULT;
+ return mIsNavigationBarShowing || mBehavior == WindowInsetsController.BEHAVIOR_DEFAULT
+ || isGesturalMode(mNavBarMode);
}
@DrawableRes
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index ef93bc311072..e9ac26182c7e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -168,7 +169,8 @@ public class RemoteTransitionCompat implements Parcelable {
}
t.apply();
mRecentsSession.setup(controller, info, finishedCallback, pausingTasks, pipTask,
- recentsTask, leashMap, mToken);
+ recentsTask, leashMap, mToken,
+ (info.getFlags() & TRANSIT_FLAG_KEYGUARD_LOCKED) != 0);
recents.onAnimationStart(mRecentsSession, apps, wallpapers, new Rect(0, 0, 0, 0),
new Rect());
}
@@ -223,12 +225,13 @@ public class RemoteTransitionCompat implements Parcelable {
private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null;
private PictureInPictureSurfaceTransaction mPipTransaction = null;
private IBinder mTransition = null;
+ private boolean mKeyguardLocked = false;
void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info,
IRemoteTransitionFinishedCallback finishCB,
ArrayList<WindowContainerToken> pausingTasks, WindowContainerToken pipTask,
WindowContainerToken recentsTask, ArrayMap<SurfaceControl, SurfaceControl> leashMap,
- IBinder transition) {
+ IBinder transition, boolean keyguardLocked) {
if (mInfo != null) {
throw new IllegalStateException("Trying to run a new recents animation while"
+ " recents is already active.");
@@ -241,6 +244,7 @@ public class RemoteTransitionCompat implements Parcelable {
mRecentsTask = recentsTask;
mLeashMap = leashMap;
mTransition = transition;
+ mKeyguardLocked = keyguardLocked;
}
@SuppressLint("NewApi")
@@ -375,6 +379,10 @@ public class RemoteTransitionCompat implements Parcelable {
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
final WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (mKeyguardLocked && mRecentsTask != null) {
+ if (toHome) wct.reorder(mRecentsTask, true /* toTop */);
+ else wct.restoreTransientOrder(mRecentsTask);
+ }
if (!toHome && mPausingTasks != null && mOpeningLeashes == null) {
// The gesture went back to opening the app rather than continuing with
// recents, so end the transition by moving the app back to the top (and also
@@ -384,7 +392,7 @@ public class RemoteTransitionCompat implements Parcelable {
wct.reorder(mPausingTasks.get(i), true /* onTop */);
t.show(mInfo.getChange(mPausingTasks.get(i)).getLeash());
}
- if (mRecentsTask != null) {
+ if (!mKeyguardLocked && mRecentsTask != null) {
wct.restoreTransientOrder(mRecentsTask);
}
} else {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
index 47df70b522f7..2f6fa145664e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -16,6 +16,8 @@
package com.android.keyguard;
+import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat;
+
import android.annotation.NonNull;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
@@ -241,10 +243,9 @@ public class KeyguardSimPinViewController
displayMessage = mView.getResources().getString(
R.string.kg_password_wrong_pin_code_pukked);
} else if (attemptsRemaining > 0) {
- msgId = isDefault ? R.plurals.kg_password_default_pin_message :
- R.plurals.kg_password_wrong_pin_code;
- displayMessage = mView.getResources()
- .getQuantityString(msgId, attemptsRemaining, attemptsRemaining);
+ msgId = isDefault ? R.string.kg_password_default_pin_message :
+ R.string.kg_password_wrong_pin_code;
+ displayMessage = icuMessageFormat(mView.getResources(), msgId, attemptsRemaining);
} else {
msgId = isDefault ? R.string.kg_sim_pin_instructions : R.string.kg_password_pin_failed;
displayMessage = mView.getResources().getString(msgId);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index 760c2ccb71b5..c0971bf8c16d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -16,6 +16,8 @@
package com.android.keyguard;
+import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat;
+
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
@@ -57,10 +59,9 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView {
if (attemptsRemaining == 0) {
displayMessage = getContext().getString(R.string.kg_password_wrong_puk_code_dead);
} else if (attemptsRemaining > 0) {
- int msgId = isDefault ? R.plurals.kg_password_default_puk_message :
- R.plurals.kg_password_wrong_puk_code;
- displayMessage = getContext().getResources()
- .getQuantityString(msgId, attemptsRemaining, attemptsRemaining);
+ int msgId = isDefault ? R.string.kg_password_default_puk_message :
+ R.string.kg_password_wrong_puk_code;
+ displayMessage = icuMessageFormat(getResources(), msgId, attemptsRemaining);
} else {
int msgId = isDefault ? R.string.kg_puk_enter_puk_hint :
R.string.kg_password_puk_failed;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 855fc241800b..83f0bcf36a43 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1571,9 +1571,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
public void onUdfpsPointerDown(int sensorId) {
Log.d(TAG, "onUdfpsPointerDown, sensorId: " + sensorId);
requestFaceAuth(true);
- if (isFaceDetectionRunning()) {
- mKeyguardBypassController.setUserHasDeviceEntryIntent(true);
- }
}
/**
@@ -1606,9 +1603,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
"faceFailure-" + reason);
handleFaceAuthFailed();
- if (mKeyguardBypassController != null) {
- mKeyguardBypassController.setUserHasDeviceEntryIntent(false);
- }
}
@Override
@@ -1616,10 +1610,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationSucceeded");
handleFaceAuthenticated(result.getUserId(), result.isStrongBiometric());
Trace.endSection();
-
- if (mKeyguardBypassController != null) {
- mKeyguardBypassController.setUserHasDeviceEntryIntent(false);
- }
}
@Override
@@ -1630,9 +1620,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
@Override
public void onAuthenticationError(int errMsgId, CharSequence errString) {
handleFaceError(errMsgId, errString.toString());
- if (mKeyguardBypassController != null) {
- mKeyguardBypassController.setUserHasDeviceEntryIntent(false);
- }
if (mActiveUnlockConfig.shouldRequestActiveUnlockOnFaceError(errMsgId)) {
requestActiveUnlock(
@@ -2315,10 +2302,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
updateFaceListeningState(BIOMETRIC_ACTION_START);
}
- public boolean isFaceAuthUserRequested() {
- return mIsFaceAuthUserRequested;
- }
-
/**
* In case face auth is running, cancel it.
*/
@@ -3179,11 +3162,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mSecureCameraLaunched = false;
}
- if (mKeyguardBypassController != null) {
- // LS visibility has changed, so reset deviceEntryIntent
- mKeyguardBypassController.setUserHasDeviceEntryIntent(false);
- }
-
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index cadd99fa532b..4ffea14a62b4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -65,6 +65,7 @@ import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.util.concurrency.DelayableExecutor;
+import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.HashSet;
@@ -804,4 +805,36 @@ public class AuthContainerView extends LinearLayout
lp.token = windowToken;
return lp;
}
+
+ @Override
+ public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println(" isAttachedToWindow=" + isAttachedToWindow());
+ pw.println(" containerState=" + mContainerState);
+ pw.println(" pendingCallbackReason=" + mPendingCallbackReason);
+ pw.println(" config exist=" + (mConfig != null));
+ if (mConfig != null) {
+ pw.println(" config.sensorIds exist=" + (mConfig.mSensorIds != null));
+ }
+ final AuthBiometricView biometricView = mBiometricView;
+ pw.println(" scrollView=" + findViewById(R.id.biometric_scrollview));
+ pw.println(" biometricView=" + biometricView);
+ if (biometricView != null) {
+ int[] ids = {
+ R.id.title,
+ R.id.subtitle,
+ R.id.description,
+ R.id.biometric_icon_frame,
+ R.id.biometric_icon,
+ R.id.indicator,
+ R.id.button_bar,
+ R.id.button_negative,
+ R.id.button_use_credential,
+ R.id.button_confirm,
+ R.id.button_try_again
+ };
+ for (final int id: ids) {
+ pw.println(" " + biometricView.findViewById(id));
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index af0a1ae88b1a..41aa112d5c7b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -76,6 +76,7 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.Execution;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@@ -1048,6 +1049,21 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
userManager, lockPatternUtils, mInteractionJankMonitor);
}
+ @Override
+ public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
+ final AuthDialog dialog = mCurrentDialog;
+ pw.println(" stableDisplaySize=" + mStableDisplaySize);
+ pw.println(" faceAuthSensorLocation=" + mFaceAuthSensorLocation);
+ pw.println(" fingerprintLocation=" + mFingerprintLocation);
+ pw.println(" udfpsBounds=" + mUdfpsBounds);
+ pw.println(" allFingerprintAuthenticatorsRegistered="
+ + mAllFingerprintAuthenticatorsRegistered);
+ pw.println(" currentDialog=" + dialog);
+ if (dialog != null) {
+ dialog.dump(pw, args);
+ }
+ }
+
/**
* Provides a float that represents the resolution scale(if the controller is for UDFPS).
*/
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
index 4ff19f6adc11..51f39b358659 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
@@ -23,13 +23,15 @@ import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.os.Bundle;
import android.view.WindowManager;
+import com.android.systemui.Dumpable;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Interface for the biometric dialog UI.
*/
-public interface AuthDialog {
+public interface AuthDialog extends Dumpable {
String KEY_CONTAINER_GOING_AWAY = "container_going_away";
String KEY_BIOMETRIC_SHOWING = "biometric_showing";
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index 3714c15af173..eab374508913 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -51,7 +51,6 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -100,7 +99,6 @@ import android.widget.TextView;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.policy.PhoneWindow;
-import com.android.settingslib.applications.InterestingConfigChanges;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.broadcast.BroadcastSender;
@@ -166,10 +164,9 @@ public class ClipboardOverlayController {
private boolean mBlockAttach = false;
private Animator mExitAnimator;
+ private Animator mEnterAnimator;
+ private final int mOrientation;
- /** Tracks config changes that require updating insets */
- private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
- ActivityInfo.CONFIG_KEYBOARD_HIDDEN);
public ClipboardOverlayController(Context context,
BroadcastDispatcher broadcastDispatcher,
@@ -255,6 +252,7 @@ public class ClipboardOverlayController {
mRemoteCopyChip.setIcon(
Icon.createWithResource(mContext, R.drawable.ic_baseline_devices_24), true);
mShareChip.setIcon(Icon.createWithResource(mContext, R.drawable.ic_screenshot_share), true);
+ mOrientation = mContext.getResources().getConfiguration().orientation;
attachWindow();
withWindowAttached(() -> {
@@ -266,9 +264,10 @@ public class ClipboardOverlayController {
@Override
public void onConfigurationChanged(Configuration overrideConfig,
int newDisplayId) {
- if (mConfigChanges.applyNewConfig(mContext.getResources())) {
- updateInsets(
- mWindowManager.getCurrentWindowMetrics().getWindowInsets());
+ if (mContext.getResources().getConfiguration().orientation
+ != mOrientation) {
+ mUiEventLogger.log(CLIPBOARD_OVERLAY_DISMISSED_OTHER);
+ hideImmediate();
}
}
@@ -366,7 +365,7 @@ public class ClipboardOverlayController {
Intent remoteCopyIntent = getRemoteCopyIntent(clipData);
// Only show remote copy if it's available.
PackageManager packageManager = mContext.getPackageManager();
- if (remoteCopyIntent != null && packageManager.resolveActivity(
+ if (packageManager.resolveActivity(
remoteCopyIntent, PackageManager.ResolveInfoFlags.of(0)) != null) {
mRemoteCopyChip.setVisibility(View.VISIBLE);
mRemoteCopyChip.setOnClickListener((v) -> {
@@ -381,7 +380,9 @@ public class ClipboardOverlayController {
withWindowAttached(() -> {
updateInsets(
mWindowManager.getCurrentWindowMetrics().getWindowInsets());
- mView.post(this::animateIn);
+ if (mEnterAnimator == null || !mEnterAnimator.isRunning()) {
+ mView.post(this::animateIn);
+ }
mView.announceForAccessibility(accessibilityAnnouncement);
});
mTimeoutHandler.resetTimeout();
@@ -652,7 +653,8 @@ public class ClipboardOverlayController {
if (mAccessibilityManager.isEnabled()) {
mDismissButton.setVisibility(View.VISIBLE);
}
- getEnterAnimation().start();
+ mEnterAnimator = getEnterAnimation();
+ mEnterAnimator.start();
}
private void animateOut() {
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java
index b54b83274f45..c68a867653d9 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java
@@ -26,6 +26,7 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.PersistableBundle;
+import android.text.Editable;
import android.util.Log;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
@@ -89,16 +90,20 @@ public class EditTextActivity extends Activity
@Override // ClipboardManager.OnPrimaryClipChangedListener
public void onPrimaryClipChanged() {
- hideImeAndFinish();
+ hideIme();
+ finish();
}
private void saveToClipboard() {
- ClipData clip = ClipData.newPlainText("text", mEditText.getText());
+ hideIme();
+ Editable editedText = mEditText.getText();
+ editedText.clearSpans();
+ ClipData clip = ClipData.newPlainText("text", editedText);
PersistableBundle extras = new PersistableBundle();
extras.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, mSensitive);
clip.getDescription().setExtras(extras);
mClipboardManager.setPrimaryClip(clip);
- hideImeAndFinish();
+ finish();
}
private void share() {
@@ -111,9 +116,8 @@ public class EditTextActivity extends Activity
startActivity(shareIntent);
}
- private void hideImeAndFinish() {
+ private void hideIme() {
InputMethodManager imm = getSystemService(InputMethodManager.class);
imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
- finish();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
index 0bc6579739db..a174ed0312c8 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
@@ -28,6 +28,7 @@ import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.RecyclerView
import com.android.systemui.R
import com.android.systemui.controls.ControlsServiceInfo
+import com.android.systemui.util.icuMessageFormat
import java.text.Collator
import java.util.concurrent.Executor
@@ -74,8 +75,10 @@ class AppAdapter(
}
override fun onCreateViewHolder(parent: ViewGroup, i: Int): Holder {
- return Holder(layoutInflater.inflate(R.layout.controls_app_item, parent, false),
- favoritesRenderer)
+ return Holder(
+ layoutInflater.inflate(R.layout.controls_app_item, parent, false),
+ favoritesRenderer
+ )
}
override fun getItemCount() = listOfServices.size
@@ -116,10 +119,10 @@ class FavoritesRenderer(
fun renderFavoritesForComponent(component: ComponentName): String? {
val qty = favoriteFunction(component)
- if (qty != 0) {
- return resources.getQuantityString(R.plurals.controls_number_of_favorites, qty, qty)
+ return if (qty != 0) {
+ icuMessageFormat(resources, R.string.controls_number_of_favorites, qty)
} else {
- return null
+ null
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 5b6ddd8471da..aeda20f16515 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -54,6 +54,7 @@ import android.hardware.fingerprint.FingerprintManager;
import android.media.AudioManager;
import android.media.IAudioService;
import android.media.MediaRouter2Manager;
+import android.media.projection.MediaProjectionManager;
import android.media.session.MediaSessionManager;
import android.net.ConnectivityManager;
import android.net.NetworkScoreManager;
@@ -321,6 +322,11 @@ public class FrameworkServicesModule {
}
@Provides
+ static MediaProjectionManager provideMediaProjectionManager(Context context) {
+ return context.getSystemService(MediaProjectionManager.class);
+ }
+
+ @Provides
static MediaRouter2Manager provideMediaRouter2Manager(Context context) {
return MediaRouter2Manager.getInstance(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 535eff801878..366ef2651a92 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -46,6 +46,7 @@ import com.android.systemui.lowlightclock.LowLightClockController;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationBarComponent;
import com.android.systemui.plugins.BcSmartspaceDataPlugin;
+import com.android.systemui.privacy.PrivacyModule;
import com.android.systemui.recents.Recents;
import com.android.systemui.screenshot.dagger.ScreenshotModule;
import com.android.systemui.settings.dagger.SettingsModule;
@@ -122,6 +123,7 @@ import dagger.Provides;
LogModule.class,
PeopleHubModule.class,
PluginModule.class,
+ PrivacyModule.class,
QsFrameTranslateModule.class,
ScreenshotModule.class,
SensorModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 19287c133651..4161cf6d2657 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -332,6 +332,20 @@ public class DozeLog implements Dumpable {
}
/**
+ * Logs the car mode started event.
+ */
+ public void traceCarModeStarted() {
+ mLogger.logCarModeStarted();
+ }
+
+ /**
+ * Logs the car mode ended event.
+ */
+ public void traceCarModeEnded() {
+ mLogger.logCarModeEnded();
+ }
+
+ /**
* Appends power save changes that may cause a new doze state
* @param powerSaveActive true if power saving is active
* @param nextState the state that we'll transition to
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
index 4c81563e4f93..4b279ec8f008 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
@@ -105,7 +105,7 @@ class DozeLogger @Inject constructor(
bool4 = screenOnFromTouch
}, {
"Fling expand=$bool1 aboveThreshold=$bool2 thresholdNeeded=$bool3 " +
- "screenOnFromTouch=$bool4"
+ "screenOnFromTouch=$bool4"
})
}
@@ -151,7 +151,7 @@ class DozeLogger @Inject constructor(
long2 = triggerAt
}, {
"Time tick scheduledAt=${DATE_FORMAT.format(Date(long1))} " +
- "triggerAt=${DATE_FORMAT.format(Date(long2))}"
+ "triggerAt=${DATE_FORMAT.format(Date(long2))}"
})
}
@@ -220,7 +220,7 @@ class DozeLogger @Inject constructor(
str1 = partUpdated
}, {
"Posture changed, posture=${DevicePostureController.devicePostureToString(int1)}" +
- " partUpdated=$str1"
+ " partUpdated=$str1"
})
}
@@ -299,6 +299,18 @@ class DozeLogger @Inject constructor(
"Doze aod dimming scrim opacity set, opacity=$long1"
})
}
+
+ fun logCarModeEnded() {
+ buffer.log(TAG, INFO, {}, {
+ "Doze car mode ended"
+ })
+ }
+
+ fun logCarModeStarted() {
+ buffer.log(TAG, INFO, {}, {
+ "Doze car mode started"
+ })
+ }
}
private const val TAG = "DozeLog"
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 5779bb307790..32bc9de40f5b 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -20,6 +20,8 @@ import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWA
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
import android.annotation.MainThread;
+import android.app.UiModeManager;
+import android.content.res.Configuration;
import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Trace;
import android.os.UserHandle;
@@ -33,7 +35,6 @@ import com.android.systemui.doze.dagger.WrappedService;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle.Wakefulness;
import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.Assert;
import com.android.systemui.util.wakelock.WakeLock;
@@ -66,6 +67,8 @@ public class DozeMachine {
INITIALIZED,
/** Regular doze. Device is asleep and listening for pulse triggers. */
DOZE,
+ /** Deep doze. Device is asleep and is not listening for pulse triggers. */
+ DOZE_SUSPEND_TRIGGERS,
/** Always-on doze. Device is asleep, showing UI and listening for pulse triggers. */
DOZE_AOD,
/** Pulse has been requested. Device is awake and preparing UI */
@@ -125,6 +128,7 @@ public class DozeMachine {
: Display.STATE_ON;
case DOZE_AOD_PAUSED:
case DOZE:
+ case DOZE_SUSPEND_TRIGGERS:
return Display.STATE_OFF;
case DOZE_PULSING:
case DOZE_PULSING_BRIGHT:
@@ -143,26 +147,27 @@ public class DozeMachine {
private final WakeLock mWakeLock;
private final AmbientDisplayConfiguration mConfig;
private final WakefulnessLifecycle mWakefulnessLifecycle;
- private final BatteryController mBatteryController;
private final DozeHost mDozeHost;
- private Part[] mParts;
+ private final UiModeManager mUiModeManager;
+ private final DockManager mDockManager;
+ private final Part[] mParts;
private final ArrayList<State> mQueuedRequests = new ArrayList<>();
private State mState = State.UNINITIALIZED;
private int mPulseReason;
private boolean mWakeLockHeldForCurrentState = false;
- private DockManager mDockManager;
@Inject
public DozeMachine(@WrappedService Service service, AmbientDisplayConfiguration config,
WakeLock wakeLock, WakefulnessLifecycle wakefulnessLifecycle,
- BatteryController batteryController, DozeLog dozeLog, DockManager dockManager,
+ UiModeManager uiModeManager,
+ DozeLog dozeLog, DockManager dockManager,
DozeHost dozeHost, Part[] parts) {
mDozeService = service;
mConfig = config;
mWakefulnessLifecycle = wakefulnessLifecycle;
mWakeLock = wakeLock;
- mBatteryController = batteryController;
+ mUiModeManager = uiModeManager;
mDozeLog = dozeLog;
mDockManager = dockManager;
mDozeHost = dozeHost;
@@ -244,7 +249,7 @@ public class DozeMachine {
Assert.isMainThread();
if (isExecutingTransition()) {
throw new IllegalStateException("Cannot get state because there were pending "
- + "transitions: " + mQueuedRequests.toString());
+ + "transitions: " + mQueuedRequests);
}
return mState;
}
@@ -313,11 +318,8 @@ public class DozeMachine {
}
mDozeLog.traceDozeStateSendComplete(newState);
- switch (newState) {
- case FINISH:
- mDozeService.finish();
- break;
- default:
+ if (newState == State.FINISH) {
+ mDozeService.finish();
}
}
@@ -357,6 +359,12 @@ public class DozeMachine {
if (mState == State.FINISH) {
return State.FINISH;
}
+ if (mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR
+ && (requestedState.canPulse() || requestedState.staysAwake())) {
+ Log.i(TAG, "Doze is suppressed with all triggers disabled as car mode is active");
+ mDozeLog.traceCarModeStarted();
+ return State.DOZE_SUSPEND_TRIGGERS;
+ }
if (mDozeHost.isAlwaysOnSuppressed() && requestedState.isAlwaysOn()) {
Log.i(TAG, "Doze is suppressed by an app. Suppressing state: " + requestedState);
mDozeLog.traceAlwaysOnSuppressed(requestedState, "app");
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index 83220cab7149..60227ee95fc2 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -147,6 +147,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
setLightSensorEnabled(true);
break;
case DOZE:
+ case DOZE_SUSPEND_TRIGGERS:
setLightSensorEnabled(false);
resetBrightnessToDefault();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java
index 89f50ad9fc21..7ed4b35e1ee7 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java
@@ -17,6 +17,7 @@
package com.android.systemui.doze;
import static android.app.UiModeManager.ACTION_ENTER_CAR_MODE;
+import static android.app.UiModeManager.ACTION_EXIT_CAR_MODE;
import android.app.UiModeManager;
import android.content.BroadcastReceiver;
@@ -96,6 +97,7 @@ public class DozeSuppressor implements DozeMachine.Part {
registerBroadcastReceiver();
mDozeHost.addCallback(mHostCallback);
checkShouldImmediatelyEndDoze();
+ checkShouldImmediatelySuspendDoze();
break;
case FINISH:
destroy();
@@ -110,11 +112,16 @@ public class DozeSuppressor implements DozeMachine.Part {
mDozeHost.removeCallback(mHostCallback);
}
+ private void checkShouldImmediatelySuspendDoze() {
+ if (mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR) {
+ mDozeLog.traceCarModeStarted();
+ mMachine.requestState(DozeMachine.State.DOZE_SUSPEND_TRIGGERS);
+ }
+ }
+
private void checkShouldImmediatelyEndDoze() {
String reason = null;
- if (mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR) {
- reason = "car_mode";
- } else if (!mDozeHost.isProvisioned()) {
+ if (!mDozeHost.isProvisioned()) {
reason = "device_unprovisioned";
} else if (mBiometricUnlockControllerLazy.get().hasPendingAuthentication()) {
reason = "has_pending_auth";
@@ -141,6 +148,7 @@ public class DozeSuppressor implements DozeMachine.Part {
return;
}
IntentFilter filter = new IntentFilter(ACTION_ENTER_CAR_MODE);
+ filter.addAction(ACTION_EXIT_CAR_MODE);
mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter);
mBroadcastReceiverRegistered = true;
}
@@ -156,9 +164,14 @@ public class DozeSuppressor implements DozeMachine.Part {
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
- mDozeLog.traceImmediatelyEndDoze("car_mode");
- mMachine.requestState(DozeMachine.State.FINISH);
+ String action = intent.getAction();
+ if (ACTION_ENTER_CAR_MODE.equals(action)) {
+ mDozeLog.traceCarModeStarted();
+ mMachine.requestState(DozeMachine.State.DOZE_SUSPEND_TRIGGERS);
+ } else if (ACTION_EXIT_CAR_MODE.equals(action)) {
+ mDozeLog.traceCarModeEnded();
+ mMachine.requestState(mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)
+ ? DozeMachine.State.DOZE_AOD : DozeMachine.State.DOZE);
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 1cc5df5d04cf..0014d6bbaf24 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -16,6 +16,10 @@
package com.android.systemui.doze;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_SUSPEND_TRIGGERS;
+import static com.android.systemui.doze.DozeMachine.State.FINISH;
+import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
+
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -437,14 +441,18 @@ public class DozeTriggers implements DozeMachine.Part {
@Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
+ if (oldState == DOZE_SUSPEND_TRIGGERS && (newState != FINISH
+ && newState != UNINITIALIZED)) {
+ // Register callbacks that were unregistered when we switched to
+ // DOZE_SUSPEND_TRIGGERS state.
+ registerCallbacks();
+ }
switch (newState) {
case INITIALIZED:
mAodInterruptRunnable = null;
sWakeDisplaySensorState = true;
- mBroadcastReceiver.register(mBroadcastDispatcher);
- mDockManager.addListener(mDockEventListener);
+ registerCallbacks();
mDozeSensors.requestTemporaryDisable();
- mDozeHost.addCallback(mHostCallback);
break;
case DOZE:
case DOZE_AOD:
@@ -472,21 +480,36 @@ public class DozeTriggers implements DozeMachine.Part {
case DOZE_PULSE_DONE:
mDozeSensors.requestTemporaryDisable();
break;
+ case DOZE_SUSPEND_TRIGGERS:
case FINISH:
- mBroadcastReceiver.unregister(mBroadcastDispatcher);
- mDozeHost.removeCallback(mHostCallback);
- mDockManager.removeListener(mDockEventListener);
- mDozeSensors.setListening(false, false);
- mDozeSensors.setProxListening(false);
- mWantSensors = false;
- mWantProxSensor = false;
- mWantTouchScreenSensors = false;
+ stopListeningToAllTriggers();
break;
default:
}
mDozeSensors.setListening(mWantSensors, mWantTouchScreenSensors);
}
+ private void registerCallbacks() {
+ mBroadcastReceiver.register(mBroadcastDispatcher);
+ mDockManager.addListener(mDockEventListener);
+ mDozeHost.addCallback(mHostCallback);
+ }
+
+ private void unregisterCallbacks() {
+ mBroadcastReceiver.unregister(mBroadcastDispatcher);
+ mDozeHost.removeCallback(mHostCallback);
+ mDockManager.removeListener(mDockEventListener);
+ }
+
+ private void stopListeningToAllTriggers() {
+ unregisterCallbacks();
+ mDozeSensors.setListening(false, false);
+ mDozeSensors.setProxListening(false);
+ mWantSensors = false;
+ mWantProxSensor = false;
+ mWantTouchScreenSensors = false;
+ }
+
@Override
public void onScreenState(int state) {
mDozeSensors.onScreenState(state);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index e568b8282856..70e4fa3aa27f 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -139,6 +139,7 @@ public class DozeUi implements DozeMachine.Part {
break;
case DOZE:
case DOZE_AOD_PAUSED:
+ case DOZE_SUSPEND_TRIGGERS:
unscheduleTimeTick();
break;
case DOZE_REQUEST_PULSE:
diff --git a/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt b/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt
index 9b0d43272fd3..f1d5e94bfbf3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt
@@ -238,5 +238,6 @@ class ColorSchemeTransition internal constructor(
fun updateColorScheme(colorScheme: ColorScheme?, enableGradient: Boolean) {
isGradientEnabled = enableGradient
colorTransitions.forEach { it.updateColorScheme(colorScheme) }
+ colorScheme?.let { mediaViewHolder.gutsViewHolder.colorScheme = colorScheme }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/GutsViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/GutsViewHolder.kt
index 1a48a84aff23..73240b54a27a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/GutsViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/GutsViewHolder.kt
@@ -40,6 +40,9 @@ class GutsViewHolder constructor(itemView: View) {
val dismissText: TextView = itemView.requireViewById(R.id.dismiss_text)
val settings: ImageButton = itemView.requireViewById(R.id.settings)
+ private var isDismissible: Boolean = true
+ var colorScheme: ColorScheme? = null
+
/** Marquees the main text of the guts menu. */
fun marquee(start: Boolean, delay: Long, tag: String) {
val gutsTextHandler = gutsText.handler
@@ -47,19 +50,31 @@ class GutsViewHolder constructor(itemView: View) {
Log.d(tag, "marquee while longPressText.getHandler() is null", Exception())
return
}
- gutsTextHandler.postDelayed( { gutsText.isSelected = start }, delay)
+ gutsTextHandler.postDelayed({ gutsText.isSelected = start }, delay)
+ }
+
+ /** Set whether this control can be dismissed, and update appearance to match */
+ fun setDismissible(dismissible: Boolean) {
+ if (isDismissible == dismissible) return
+
+ isDismissible = dismissible
+ colorScheme?.let { setColors(it) }
}
/** Sets the right colors on all the guts views based on the given [ColorScheme]. */
- fun setColors(colorScheme: ColorScheme) {
- setSurfaceColor(surfaceFromScheme(colorScheme))
- setTextPrimaryColor(textPrimaryFromScheme(colorScheme))
- setAccentPrimaryColor(accentPrimaryFromScheme(colorScheme))
+ fun setColors(scheme: ColorScheme) {
+ colorScheme = scheme
+ setSurfaceColor(surfaceFromScheme(scheme))
+ setTextPrimaryColor(textPrimaryFromScheme(scheme))
+ setAccentPrimaryColor(accentPrimaryFromScheme(scheme))
}
/** Sets the surface color on all guts views that use it. */
fun setSurfaceColor(surfaceColor: Int) {
dismissText.setTextColor(surfaceColor)
+ if (!isDismissible) {
+ cancelText.setTextColor(surfaceColor)
+ }
}
/** Sets the primary accent color on all guts views that use it. */
@@ -74,7 +89,9 @@ class GutsViewHolder constructor(itemView: View) {
fun setTextPrimaryColor(textPrimary: Int) {
val textColorList = ColorStateList.valueOf(textPrimary)
gutsText.setTextColor(textColorList)
- cancelText.setTextColor(textColorList)
+ if (isDismissible) {
+ cancelText.setTextColor(textColorList)
+ }
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 972e93b886b8..e43ae0fccca7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -70,6 +70,7 @@ import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.GhostedViewLaunchAnimatorController;
import com.android.systemui.animation.Interpolators;
+import com.android.systemui.bluetooth.BroadcastDialogController;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
@@ -188,6 +189,11 @@ public class MediaControlPanel {
private final SeekBarViewModel.EnabledChangeListener mEnabledChangeListener =
this::setIsSeekBarEnabled;
+ private final BroadcastDialogController mBroadcastDialogController;
+ private boolean mIsCurrentBroadcastedApp = false;
+ private boolean mShowBroadcastDialogButton = false;
+ private String mSwitchBroadcastApp;
+
/**
* Initialize a new control panel
*
@@ -213,7 +219,8 @@ public class MediaControlPanel {
MediaUiEventLogger logger,
KeyguardStateController keyguardStateController,
ActivityIntentHelper activityIntentHelper,
- NotificationLockscreenUserManager lockscreenUserManager) {
+ NotificationLockscreenUserManager lockscreenUserManager,
+ BroadcastDialogController broadcastDialogController) {
mContext = context;
mBackgroundExecutor = backgroundExecutor;
mMainExecutor = mainExecutor;
@@ -230,6 +237,7 @@ public class MediaControlPanel {
mKeyguardStateController = keyguardStateController;
mActivityIntentHelper = activityIntentHelper;
mLockscreenUserManager = lockscreenUserManager;
+ mBroadcastDialogController = broadcastDialogController;
mSeekBarViewModel.setLogSeek(() -> {
if (mPackageName != null && mInstanceId != null) {
@@ -449,7 +457,10 @@ public class MediaControlPanel {
final MediaController controller = getController();
mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller));
- bindOutputSwitcherChip(data);
+ // Show the broadcast dialog button only when the le audio is enabled.
+ mShowBroadcastDialogButton =
+ data.getDevice() != null && data.getDevice().getShowBroadcastButton();
+ bindOutputSwitcherAndBroadcastButton(mShowBroadcastDialogButton, data);
bindGutsMenuForPlayer(data);
bindPlayerContentDescription(data);
bindScrubbingTime(data);
@@ -467,21 +478,40 @@ public class MediaControlPanel {
Trace.endSection();
}
- private void bindOutputSwitcherChip(MediaData data) {
- // Output switcher chip
+ private void bindOutputSwitcherAndBroadcastButton(boolean showBroadcastButton, MediaData data) {
ViewGroup seamlessView = mMediaViewHolder.getSeamless();
seamlessView.setVisibility(View.VISIBLE);
ImageView iconView = mMediaViewHolder.getSeamlessIcon();
TextView deviceName = mMediaViewHolder.getSeamlessText();
final MediaDeviceData device = data.getDevice();
- // Disable clicking on output switcher for invalid devices and resumption controls
- final boolean seamlessDisabled = (device != null && !device.getEnabled())
- || data.getResumption();
- final float seamlessAlpha = seamlessDisabled ? DISABLED_ALPHA : 1.0f;
- mMediaViewHolder.getSeamlessButton().setAlpha(seamlessAlpha);
- seamlessView.setEnabled(!seamlessDisabled);
- CharSequence deviceString = mContext.getString(R.string.media_seamless_other_device);
+ final boolean enabled;
+ final boolean seamlessDisabled;
+ final int iconResource;
+ CharSequence deviceString;
+ if (showBroadcastButton) {
+ // TODO(b/233698402): Use the package name instead of app label to avoid the
+ // unexpected result.
+ mIsCurrentBroadcastedApp = device != null
+ && TextUtils.equals(device.getName(),
+ MediaDataUtils.getAppLabel(mContext, mPackageName, mContext.getString(
+ R.string.bt_le_audio_broadcast_dialog_unknown_name)));
+ seamlessDisabled = !mIsCurrentBroadcastedApp;
+ // Always be enabled if the broadcast button is shown
+ enabled = true;
+ deviceString = mContext.getString(R.string.bt_le_audio_broadcast_dialog_unknown_name);
+ iconResource = R.drawable.settings_input_antenna;
+ } else {
+ // Disable clicking on output switcher for invalid devices and resumption controls
+ seamlessDisabled = (device != null && !device.getEnabled()) || data.getResumption();
+ enabled = !seamlessDisabled;
+ deviceString = mContext.getString(R.string.media_seamless_other_device);
+ iconResource = R.drawable.ic_media_home_devices;
+ }
+
+ mMediaViewHolder.getSeamlessButton().setAlpha(seamlessDisabled ? DISABLED_ALPHA : 1.0f);
+ seamlessView.setEnabled(enabled);
+
if (device != null) {
Drawable icon = device.getIcon();
if (icon instanceof AdaptiveIcon) {
@@ -494,7 +524,7 @@ public class MediaControlPanel {
deviceString = device.getName();
} else {
// Set to default icon
- iconView.setImageResource(R.drawable.ic_media_home_devices);
+ iconView.setImageResource(iconResource);
}
deviceName.setText(deviceString);
seamlessView.setContentDescription(deviceString);
@@ -503,21 +533,39 @@ public class MediaControlPanel {
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
return;
}
- mLogger.logOpenOutputSwitcher(mUid, mPackageName, mInstanceId);
- if (device.getIntent() != null) {
- if (device.getIntent().isActivity()) {
- mActivityStarter.startActivity(
- device.getIntent().getIntent(), true);
+
+ if (showBroadcastButton) {
+ // If the current media app is not broadcasted and users press the outputer
+ // button, we should pop up the broadcast dialog to check do they want to
+ // switch broadcast to the other media app, otherwise we still pop up the
+ // media output dialog.
+ if (!mIsCurrentBroadcastedApp) {
+ mLogger.logOpenBroadcastDialog(mUid, mPackageName, mInstanceId);
+ mSwitchBroadcastApp = device.getName().toString();
+ mBroadcastDialogController.createBroadcastDialog(mSwitchBroadcastApp,
+ mPackageName, true, mMediaViewHolder.getSeamlessButton());
} else {
- try {
- device.getIntent().send();
- } catch (PendingIntent.CanceledException e) {
- Log.e(TAG, "Device pending intent was canceled");
- }
+ mLogger.logOpenOutputSwitcher(mUid, mPackageName, mInstanceId);
+ mMediaOutputDialogFactory.create(mPackageName, true,
+ mMediaViewHolder.getSeamlessButton());
}
} else {
- mMediaOutputDialogFactory.create(mPackageName, true,
- mMediaViewHolder.getSeamlessButton());
+ mLogger.logOpenOutputSwitcher(mUid, mPackageName, mInstanceId);
+ if (device.getIntent() != null) {
+ if (device.getIntent().isActivity()) {
+ mActivityStarter.startActivity(
+ device.getIntent().getIntent(), true);
+ } else {
+ try {
+ device.getIntent().send();
+ } catch (PendingIntent.CanceledException e) {
+ Log.e(TAG, "Device pending intent was canceled");
+ }
+ }
+ } else {
+ mMediaOutputDialogFactory.create(mPackageName, true,
+ mMediaViewHolder.getSeamlessButton());
+ }
}
});
}
@@ -1183,7 +1231,7 @@ public class MediaControlPanel {
gutsViewHolder.getGutsText().setText(text);
// Dismiss button
- gutsViewHolder.getDismissText().setAlpha(isDismissible ? 1 : DISABLED_ALPHA);
+ gutsViewHolder.getDismissText().setVisibility(isDismissible ? View.VISIBLE : View.GONE);
gutsViewHolder.getDismiss().setEnabled(isDismissible);
gutsViewHolder.getDismiss().setOnClickListener(v -> {
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
@@ -1194,11 +1242,18 @@ public class MediaControlPanel {
});
// Cancel button
+ TextView cancelText = gutsViewHolder.getCancelText();
+ if (isDismissible) {
+ cancelText.setBackground(mContext.getDrawable(R.drawable.qs_media_outline_button));
+ } else {
+ cancelText.setBackground(mContext.getDrawable(R.drawable.qs_media_solid_button));
+ }
gutsViewHolder.getCancel().setOnClickListener(v -> {
if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
closeGuts();
}
});
+ gutsViewHolder.setDismissible(isDismissible);
// Settings button
gutsViewHolder.getSettings().setOnClickListener(v -> {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControllerFactory.java b/packages/SystemUI/src/com/android/systemui/media/MediaControllerFactory.java
index 71bc7c20c026..ed3e10939b6a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControllerFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControllerFactory.java
@@ -16,6 +16,7 @@
package com.android.systemui.media;
+import android.annotation.NonNull;
import android.content.Context;
import android.media.session.MediaController;
import android.media.session.MediaSession;
@@ -39,7 +40,7 @@ public class MediaControllerFactory {
*
* @param token The token for the session. This value must never be null.
*/
- public MediaController create(MediaSession.Token token) {
+ public MediaController create(@NonNull MediaSession.Token token) {
return new MediaController(mContext, token);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
index 360f86548e13..b2ab12a81bcc 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
@@ -215,5 +215,8 @@ data class MediaDeviceData
val intent: PendingIntent? = null,
/** Unique id for this device */
- val id: String? = null
+ val id: String? = null,
+
+ /** Whether or not to show the broadcast button */
+ val showBroadcastButton: Boolean
)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 8bf2c6e92105..30ba476abce2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -509,6 +509,11 @@ class MediaDataManager(
*/
private fun updateState(key: String, state: PlaybackState) {
mediaEntries.get(key)?.let {
+ val token = it.token
+ if (token == null) {
+ if (DEBUG) Log.d(TAG, "State updated, but token was null")
+ return
+ }
val actions = createActionsFromState(it.packageName,
mediaControllerFactory.create(it.token), UserHandle(it.userId))
val data = it.copy(
@@ -681,7 +686,8 @@ class MediaDataManager(
val enabled = deviceIntent != null && deviceIntent.isActivity
val deviceDrawable = Icon.createWithResource(sbn.packageName, deviceIcon)
.loadDrawable(sbn.getPackageContext(context))
- device = MediaDeviceData(enabled, deviceDrawable, deviceName, deviceIntent)
+ device = MediaDeviceData(enabled, deviceDrawable, deviceName, deviceIntent,
+ showBroadcastButton = false)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
index 8558859638d5..b552d9fb584a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
@@ -16,15 +16,23 @@
package com.android.systemui.media
+import android.bluetooth.BluetoothLeBroadcast
+import android.bluetooth.BluetoothLeBroadcastMetadata
+import android.content.Context
import android.graphics.drawable.Drawable
import android.media.MediaRouter2Manager
import android.media.session.MediaController
+import android.text.TextUtils
+import android.util.Log
import androidx.annotation.AnyThread
import androidx.annotation.MainThread
import androidx.annotation.WorkerThread
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
+import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.settingslib.media.LocalMediaManager
import com.android.settingslib.media.MediaDevice
import com.android.systemui.Dumpable
+import com.android.systemui.R
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
@@ -36,16 +44,20 @@ import java.util.concurrent.Executor
import javax.inject.Inject
private const val PLAYBACK_TYPE_UNKNOWN = 0
+private const val TAG = "MediaDeviceManager"
+private const val DEBUG = true
/**
* Provides information about the route (ie. device) where playback is occurring.
*/
class MediaDeviceManager @Inject constructor(
+ private val context: Context,
private val controllerFactory: MediaControllerFactory,
private val localMediaManagerFactory: LocalMediaManagerFactory,
private val mr2manager: MediaRouter2Manager,
private val muteAwaitConnectionManagerFactory: MediaMuteAwaitConnectionManagerFactory,
private val configurationController: ConfigurationController,
+ private val localBluetoothManager: LocalBluetoothManager?,
@Main private val fgExecutor: Executor,
@Background private val bgExecutor: Executor,
dumpManager: DumpManager
@@ -147,7 +159,8 @@ class MediaDeviceManager @Inject constructor(
val controller: MediaController?,
val localMediaManager: LocalMediaManager,
val muteAwaitConnectionManager: MediaMuteAwaitConnectionManager?
- ) : LocalMediaManager.DeviceCallback, MediaController.Callback() {
+ ) : LocalMediaManager.DeviceCallback, MediaController.Callback(),
+ BluetoothLeBroadcast.Callback {
val token
get() = controller?.sessionToken
@@ -166,7 +179,7 @@ class MediaDeviceManager @Inject constructor(
// A device that is not yet connected but is expected to connect imminently. Because it's
// expected to connect imminently, it should be displayed as the current device.
private var aboutToConnectDeviceOverride: AboutToConnectDevice? = null
-
+ private var broadcastDescription: String? = null
private val configListener = object : ConfigurationController.ConfigurationListener {
override fun onLocaleListChanged() {
updateCurrent()
@@ -238,7 +251,11 @@ class MediaDeviceManager @Inject constructor(
) {
aboutToConnectDeviceOverride = AboutToConnectDevice(
fullMediaDevice = localMediaManager.getMediaDeviceById(deviceAddress),
- backupMediaDeviceData = MediaDeviceData(enabled = true, deviceIcon, deviceName)
+ backupMediaDeviceData = MediaDeviceData(
+ /* enabled */ enabled = true,
+ /* icon */ deviceIcon,
+ /* name */ deviceName,
+ /* showBroadcastButton */ showBroadcastButton = false)
)
updateCurrent()
}
@@ -248,23 +265,127 @@ class MediaDeviceManager @Inject constructor(
updateCurrent()
}
+
+ override fun onBroadcastStarted(reason: Int, broadcastId: Int) {
+ if (DEBUG) {
+ Log.d(TAG, "onBroadcastStarted(), reason = $reason , broadcastId = $broadcastId")
+ }
+ updateCurrent()
+ }
+
+ override fun onBroadcastStartFailed(reason: Int) {
+ if (DEBUG) {
+ Log.d(TAG, "onBroadcastStartFailed(), reason = $reason")
+ }
+ }
+
+ override fun onBroadcastMetadataChanged(broadcastId: Int,
+ metadata: BluetoothLeBroadcastMetadata) {
+ if (DEBUG) {
+ Log.d(TAG, "onBroadcastMetadataChanged(), broadcastId = $broadcastId , " +
+ "metadata = $metadata")
+ }
+ updateCurrent()
+ }
+
+ override fun onBroadcastStopped(reason: Int, broadcastId: Int) {
+ if (DEBUG) {
+ Log.d(TAG, "onBroadcastStopped(), reason = $reason , broadcastId = $broadcastId")
+
+ }
+ updateCurrent()
+ }
+
+ override fun onBroadcastStopFailed(reason: Int) {
+ if (DEBUG) {
+ Log.d(TAG, "onBroadcastStopFailed(), reason = $reason")
+ }
+ }
+
+ override fun onBroadcastUpdated(reason: Int, broadcastId: Int) {
+ if (DEBUG) {
+ Log.d(TAG, "onBroadcastUpdated(), reason = $reason , broadcastId = $broadcastId")
+ }
+ updateCurrent()
+ }
+
+ override fun onBroadcastUpdateFailed(reason: Int, broadcastId: Int) {
+ if (DEBUG) {
+ Log.d(TAG, "onBroadcastUpdateFailed(), reason = $reason , " +
+ "broadcastId = $broadcastId")
+ }
+ }
+
+ override fun onPlaybackStarted(reason: Int, broadcastId: Int) {}
+
+ override fun onPlaybackStopped(reason: Int, broadcastId: Int) {}
+
@WorkerThread
private fun updateCurrent() {
- val aboutToConnect = aboutToConnectDeviceOverride
- if (aboutToConnect != null &&
- aboutToConnect.fullMediaDevice == null &&
- aboutToConnect.backupMediaDeviceData != null) {
+ if (isLeAudioBroadcastEnabled()) {
+ current = MediaDeviceData(
+ /* enabled */ true,
+ /* icon */ context.getDrawable(R.drawable.settings_input_antenna),
+ /* name */ broadcastDescription,
+ /* intent */ null,
+ /* showBroadcastButton */ showBroadcastButton = true)
+ } else {
+ val aboutToConnect = aboutToConnectDeviceOverride
+ if (aboutToConnect != null &&
+ aboutToConnect.fullMediaDevice == null &&
+ aboutToConnect.backupMediaDeviceData != null) {
// Only use [backupMediaDeviceData] when we don't have [fullMediaDevice].
current = aboutToConnect.backupMediaDeviceData
return
+ }
+ val device = aboutToConnect?.fullMediaDevice
+ ?: localMediaManager.currentConnectedDevice
+ val route = controller?.let { mr2manager.getRoutingSessionForMediaController(it) }
+
+ // If we have a controller but get a null route, then don't trust the device
+ val enabled = device != null && (controller == null || route != null)
+ val name = route?.name?.toString() ?: device?.name
+ current = MediaDeviceData(enabled, device?.iconWithoutBackground, name,
+ id = device?.id, showBroadcastButton = false)
}
- val device = aboutToConnect?.fullMediaDevice ?: localMediaManager.currentConnectedDevice
- val route = controller?.let { mr2manager.getRoutingSessionForMediaController(it) }
+ }
- // If we have a controller but get a null route, then don't trust the device
- val enabled = device != null && (controller == null || route != null)
- val name = route?.name?.toString() ?: device?.name
- current = MediaDeviceData(enabled, device?.iconWithoutBackground, name, id = device?.id)
+ private fun isLeAudioBroadcastEnabled(): Boolean {
+ if (localBluetoothManager != null) {
+ val profileManager = localBluetoothManager.profileManager
+ if (profileManager != null) {
+ val bluetoothLeBroadcast = profileManager.leAudioBroadcastProfile
+ if (bluetoothLeBroadcast != null && bluetoothLeBroadcast.isEnabled(null)) {
+ getBroadcastingInfo(bluetoothLeBroadcast)
+ return true
+ } else if (DEBUG) {
+ Log.d(TAG, "Can not get LocalBluetoothLeBroadcast")
+ }
+ } else if (DEBUG) {
+ Log.d(TAG, "Can not get LocalBluetoothProfileManager")
+ }
+ } else if (DEBUG) {
+ Log.d(TAG, "Can not get LocalBluetoothManager")
+ }
+ return false
+ }
+
+ private fun getBroadcastingInfo(bluetoothLeBroadcast: LocalBluetoothLeBroadcast) {
+ var currentBroadcastedApp = bluetoothLeBroadcast.appSourceName
+ // TODO(b/233698402): Use the package name instead of app label to avoid the
+ // unexpected result.
+ // Check the current media app's name is the same with current broadcast app's name
+ // or not.
+ var mediaApp = MediaDataUtils.getAppLabel(
+ context, localMediaManager.packageName,
+ context.getString(R.string.bt_le_audio_broadcast_dialog_unknown_name))
+ var isCurrentBroadcastedApp = TextUtils.equals(mediaApp, currentBroadcastedApp)
+ if (isCurrentBroadcastedApp) {
+ broadcastDescription = context.getString(
+ R.string.broadcasting_description_is_broadcasting)
+ } else {
+ broadcastDescription = currentBroadcastedApp
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
index d4c4f2165339..93a29ef03393 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
@@ -161,8 +161,9 @@ class MediaTimeoutListener @Inject constructor(
destroyed = false
mediaController?.unregisterCallback(this)
field = value
- mediaController = if (field.token != null) {
- mediaControllerFactory.create(field.token)
+ val token = field.token
+ mediaController = if (token != null) {
+ mediaControllerFactory.create(token)
} else {
null
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaUiEventLogger.kt b/packages/SystemUI/src/com/android/systemui/media/MediaUiEventLogger.kt
index 52f5cc568ba4..0baf01e7476f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaUiEventLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaUiEventLogger.kt
@@ -176,6 +176,11 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
logger.logWithInstanceId(MediaUiEvent.MEDIA_RECOMMENDATION_CARD_TAP, 0, packageName,
instanceId)
}
+
+ fun logOpenBroadcastDialog(uid: Int, packageName: String, instanceId: InstanceId) {
+ logger.logWithInstanceId(MediaUiEvent.MEDIA_OPEN_BROADCAST_DIALOG, uid, packageName,
+ instanceId)
+ }
}
enum class MediaUiEvent(val metricId: Int) : UiEventLogger.UiEventEnum {
@@ -273,7 +278,10 @@ enum class MediaUiEvent(val metricId: Int) : UiEventLogger.UiEventEnum {
MEDIA_RECOMMENDATION_ITEM_TAP(1044),
@UiEvent(doc = "User tapped on a media recommendation card")
- MEDIA_RECOMMENDATION_CARD_TAP(1045);
+ MEDIA_RECOMMENDATION_CARD_TAP(1045),
+
+ @UiEvent(doc = "User opened the broadcast dialog from a media control")
+ MEDIA_OPEN_BROADCAST_DIALOG(1079);
override fun getId() = metricId
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
index deb5cbafccc4..27cd1ce2b440 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
@@ -270,8 +270,11 @@ class MediaViewController @Inject constructor(
}
}
gutsIds.forEach { id ->
- viewState.widgetStates.get(id)?.alpha = if (isGutsVisible) 1f else 0f
- viewState.widgetStates.get(id)?.gone = !isGutsVisible
+ viewState.widgetStates.get(id)?.let { state ->
+ // Make sure to use the unmodified state if guts are visible
+ state.alpha = if (isGutsVisible) state.alpha else 0f
+ state.gone = if (isGutsVisible) state.gone else true
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
index 60ef85d0b502..121021f19f70 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
@@ -99,7 +99,9 @@ open class SeekBarObserver(
holder.seekBar.setMax(data.duration)
val totalTimeString = DateUtils.formatElapsedTime(
data.duration / DateUtils.SECOND_IN_MILLIS)
- holder.scrubbingTotalTimeView.text = totalTimeString
+ if (data.scrubbing) {
+ holder.scrubbingTotalTimeView.text = totalTimeString
+ }
data.elapsedTime?.let {
if (!data.scrubbing && !(seekBarResetAnimator?.isRunning ?: false)) {
@@ -113,9 +115,12 @@ open class SeekBarObserver(
holder.seekBar.progress = it
}
}
+
val elapsedTimeString = DateUtils.formatElapsedTime(
it / DateUtils.SECOND_IN_MILLIS)
- holder.scrubbingElapsedTimeView.text = elapsedTimeString
+ if (data.scrubbing) {
+ holder.scrubbingElapsedTimeView.text = elapsedTimeString
+ }
holder.seekBar.contentDescription = holder.seekBar.context.getString(
R.string.controls_media_seekbar_description,
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index ec472c655b43..5430ee67e6ef 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -28,7 +28,6 @@ import android.widget.CheckBox;
import androidx.annotation.NonNull;
import androidx.core.widget.CompoundButtonCompat;
-import com.android.settingslib.Utils;
import com.android.settingslib.media.LocalMediaManager.MediaDeviceState;
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.R;
@@ -257,9 +256,8 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
setSingleLineLayout(mContext.getText(R.string.media_output_dialog_pairing_new),
false /* bFocused */);
final Drawable d = mContext.getDrawable(R.drawable.ic_add);
- d.setColorFilter(new PorterDuffColorFilter(
- Utils.getColorAccentDefaultColor(mContext), PorterDuff.Mode.SRC_IN));
mTitleIcon.setImageDrawable(d);
+ mTitleIcon.setColorFilter(mController.getColorItemContent());
mContainerLayout.setOnClickListener(mController::launchBluetoothPairing);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 3fc9afe6ea94..ad3cfa359a52 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -812,6 +812,7 @@ public class NavigationBarView extends FrameLayout {
mImeDrawsImeNavBar = imeDrawsImeNavBar;
mBarTransitions.onNavigationModeChanged(mNavBarMode);
mEdgeBackGestureHandler.onNavigationModeChanged(mNavBarMode);
+ mRotationButtonController.onNavigationModeChanged(mNavBarMode);
updateRotationButton();
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt
index 56ad19ae89ca..282243563952 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt
@@ -58,14 +58,16 @@ class BackPanel(context: Context, private val latencyTracker: LatencyTracker) :
SpringForce().apply {
stiffness = 600f
dampingRatio = 0.65f
- })
+ }
+ )
private val backgroundHeight = AnimatedFloat(
name = "backgroundHeight",
SpringForce().apply {
stiffness = 600f
dampingRatio = 0.65f
- })
+ }
+ )
/**
* Corners of the background closer to the edge of the screen (where the arrow appeared from).
@@ -76,18 +78,20 @@ class BackPanel(context: Context, private val latencyTracker: LatencyTracker) :
SpringForce().apply {
stiffness = 400f
dampingRatio = SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY
- })
+ }
+ )
/**
* Corners of the background further from the edge of the screens (toward the direction the
* arrow is being dragged). Used for animating [arrowBackgroundRect]
*/
- private val backgroundDragCornerRadius = AnimatedFloat(
+ private val backgroundFarCornerRadius = AnimatedFloat(
name = "backgroundDragCornerRadius",
SpringForce().apply {
stiffness = 2200f
dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
- })
+ }
+ )
/**
* Left/right position of the background relative to the canvas. Also corresponds with the
@@ -96,14 +100,32 @@ class BackPanel(context: Context, private val latencyTracker: LatencyTracker) :
*/
private var horizontalTranslation = AnimatedFloat("horizontalTranslation", SpringForce())
+ private val currentAlpha: FloatPropertyCompat<BackPanel> =
+ object : FloatPropertyCompat<BackPanel>("currentAlpha") {
+ override fun setValue(panel: BackPanel, value: Float) {
+ panel.alpha = value
+ }
+
+ override fun getValue(panel: BackPanel): Float = panel.alpha
+ }
+
+ private val alphaAnimation = SpringAnimation(this, currentAlpha)
+ .setSpring(
+ SpringForce()
+ .setStiffness(60f)
+ .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY)
+ )
+
/**
* Canvas vertical translation. How far up/down the arrow and background appear relative to the
* canvas.
*/
- private var verticalTranslation: AnimatedFloat =
- AnimatedFloat("verticalTranslation", SpringForce().apply {
+ private var verticalTranslation: AnimatedFloat = AnimatedFloat(
+ name = "verticalTranslation",
+ SpringForce().apply {
stiffness = SpringForce.STIFFNESS_MEDIUM
- })
+ }
+ )
/**
* Use for drawing debug info. Can only be set if [DEBUG]=true
@@ -160,6 +182,17 @@ class BackPanel(context: Context, private val latencyTracker: LatencyTracker) :
animation.animateToFinalPosition(restingPosition + stretchAmount)
}
+ /**
+ * Animates to a new position ([finalPosition]) that is the given fraction ([amount])
+ * between the existing [restingPosition] and the new [finalPosition].
+ *
+ * The [restingPosition] will remain unchanged. Only the animation is updated.
+ */
+ fun stretchBy(finalPosition: Float, amount: Float) {
+ val stretchedAmount = amount * (finalPosition - restingPosition)
+ animation.animateToFinalPosition(restingPosition + stretchedAmount)
+ }
+
fun updateRestingPosition(pos: Float, animated: Boolean) {
restingPosition = pos
if (animated)
@@ -192,7 +225,10 @@ class BackPanel(context: Context, private val latencyTracker: LatencyTracker) :
}
fun addEndListener(endListener: DelayedOnAnimationEndListener): Boolean {
- return if (horizontalTranslation.animation.isRunning) {
+ return if (alphaAnimation.isRunning) {
+ alphaAnimation.addEndListener(endListener)
+ true
+ } else if (horizontalTranslation.animation.isRunning) {
horizontalTranslation.animation.addEndListener(endListener)
true
} else {
@@ -202,47 +238,59 @@ class BackPanel(context: Context, private val latencyTracker: LatencyTracker) :
}
fun setStretch(
- arrowLengthStretch: Float,
- arrowHeightStretch: Float,
- backgroundWidthStretch: Float,
- backgroundHeightStretch: Float,
- backgroundEdgeCornerRadiusStretch: Float,
- backgroundDragCornerRadiusStretch: Float,
- horizontalTranslationStretch: Float
+ horizontalTranslationStretchAmount: Float,
+ arrowStretchAmount: Float,
+ backgroundWidthStretchAmount: Float,
+ fullyStretchedDimens: EdgePanelParams.BackIndicatorDimens
) {
- arrowLength.stretchTo(arrowLengthStretch)
- arrowHeight.stretchTo(arrowHeightStretch)
- backgroundWidth.stretchTo(backgroundWidthStretch)
- backgroundHeight.stretchTo(backgroundHeightStretch)
- backgroundEdgeCornerRadius.stretchTo(backgroundEdgeCornerRadiusStretch)
- backgroundDragCornerRadius.stretchTo(backgroundDragCornerRadiusStretch)
- horizontalTranslation.stretchTo(horizontalTranslationStretch)
+ horizontalTranslation.stretchBy(
+ finalPosition = fullyStretchedDimens.horizontalTranslation,
+ amount = horizontalTranslationStretchAmount
+ )
+ arrowLength.stretchBy(
+ finalPosition = fullyStretchedDimens.arrowDimens.length,
+ amount = arrowStretchAmount
+ )
+ arrowHeight.stretchBy(
+ finalPosition = fullyStretchedDimens.arrowDimens.height,
+ amount = arrowStretchAmount
+ )
+ backgroundWidth.stretchBy(
+ finalPosition = fullyStretchedDimens.backgroundDimens.width,
+ amount = backgroundWidthStretchAmount
+ )
}
fun resetStretch() {
- setStretch(0f, 0f, 0f, 0f, 0f, 0f, 0f)
+ horizontalTranslation.stretchTo(0f)
+ arrowLength.stretchTo(0f)
+ arrowHeight.stretchTo(0f)
+ backgroundWidth.stretchTo(0f)
+ backgroundHeight.stretchTo(0f)
+ backgroundEdgeCornerRadius.stretchTo(0f)
+ backgroundFarCornerRadius.stretchTo(0f)
}
/**
* Updates resting arrow and background size not accounting for stretch
*/
- internal fun updateRestingArrowDimens(
- backgroundWidth: Float,
- backgroundHeight: Float,
- backgroundEdgeCornerRadius: Float,
- backgroundDragCornerRadius: Float,
- arrowLength: Float,
- arrowHeight: Float,
- horizontalTranslation: Float,
+ internal fun setRestingDimens(
+ restingParams: EdgePanelParams.BackIndicatorDimens,
animate: Boolean
) {
- this.arrowLength.updateRestingPosition(arrowLength, animate)
- this.arrowHeight.updateRestingPosition(arrowHeight, animate)
- this.backgroundWidth.updateRestingPosition(backgroundWidth, animate)
- this.backgroundHeight.updateRestingPosition(backgroundHeight, animate)
- this.backgroundEdgeCornerRadius.updateRestingPosition(backgroundEdgeCornerRadius, animate)
- this.backgroundDragCornerRadius.updateRestingPosition(backgroundDragCornerRadius, animate)
- this.horizontalTranslation.updateRestingPosition(horizontalTranslation, animate)
+ horizontalTranslation.updateRestingPosition(restingParams.horizontalTranslation, animate)
+ arrowLength.updateRestingPosition(restingParams.arrowDimens.length, animate)
+ arrowHeight.updateRestingPosition(restingParams.arrowDimens.height, animate)
+ backgroundWidth.updateRestingPosition(restingParams.backgroundDimens.width, animate)
+ backgroundHeight.updateRestingPosition(restingParams.backgroundDimens.height, animate)
+ backgroundEdgeCornerRadius.updateRestingPosition(
+ restingParams.backgroundDimens.edgeCornerRadius,
+ animate
+ )
+ backgroundFarCornerRadius.updateRestingPosition(
+ restingParams.backgroundDimens.farCornerRadius,
+ animate
+ )
}
fun animateVertically(yPos: Float) = verticalTranslation.stretchTo(yPos)
@@ -262,7 +310,7 @@ class BackPanel(context: Context, private val latencyTracker: LatencyTracker) :
override fun onDraw(canvas: Canvas) {
var edgeCorner = backgroundEdgeCornerRadius.pos
- val farCorner = backgroundDragCornerRadius.pos
+ val farCorner = backgroundFarCornerRadius.pos
val halfHeight = backgroundHeight.pos / 2
canvas.save()
@@ -337,4 +385,13 @@ class BackPanel(context: Context, private val latencyTracker: LatencyTracker) :
)
addRoundRect(this@toPathWithRoundCorners, corners, Path.Direction.CW)
}
+
+ fun cancelAlphaAnimations() {
+ alphaAnimation.cancel()
+ alpha = 1f
+ }
+
+ fun fadeOut() {
+ alphaAnimation.animateToFinalPosition(0f)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
index 100411b1cb93..f1dd5ffd2077 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
@@ -31,7 +31,7 @@ import android.view.MotionEvent
import android.view.VelocityTracker
import android.view.View
import android.view.WindowManager
-import android.view.animation.AccelerateInterpolator
+import android.view.animation.DecelerateInterpolator
import android.view.animation.PathInterpolator
import android.window.BackEvent
import androidx.dynamicanimation.animation.DynamicAnimation
@@ -68,7 +68,7 @@ private const val GESTURE_DURATION_FOR_CLICK_MS = 400
/**
* The min duration arrow remains on screen during a fling event.
*/
-private const val FLING_PAUSE_DURATION_MS = 50L
+private const val FLING_MIN_APPEARANCE_DURATION = 235L
/**
* The min duration arrow remains on screen during a fling event.
@@ -90,7 +90,9 @@ private const val ARROW_DISAPPEAR_DAMPING_RATIO = SpringForce.DAMPING_RATIO_NO_B
*/
private val RUBBER_BAND_INTERPOLATOR = PathInterpolator(1.0f / 5.0f, 1.0f, 1.0f, 1.0f)
-private val ACCELERATE_INTERPOLATOR = AccelerateInterpolator(0.7f)
+private val DECELERATE_INTERPOLATOR = DecelerateInterpolator()
+
+private val DECELERATE_INTERPOLATOR_SLOW = DecelerateInterpolator(0.7f)
class BackPanelController private constructor(
context: Context,
@@ -160,6 +162,8 @@ class BackPanelController private constructor(
private var startX = 0f
private var startY = 0f
+ private var gestureStartTime = 0L
+
private val failsafeRunnable = Runnable { onFailsafe() }
private enum class GestureState {
@@ -182,19 +186,29 @@ class BackPanelController private constructor(
COMMITTED,
/* back action currently cancelling, arrow soon to be GONE */
- CANCELLED
+ CANCELLED;
+
+ /**
+ * @return true if the current state responds to touch move events in some way (e.g. by
+ * stretching the back indicator)
+ */
+ fun isInteractive(): Boolean {
+ return when (this) {
+ ENTRY, ACTIVE, INACTIVE -> true
+ GONE, FLUNG, COMMITTED, CANCELLED -> false
+ }
+ }
}
/**
* Wrapper around OnAnimationEndListener which runs the given runnable after a delay. The
* runnable is not called if the animation is cancelled
*/
- class DelayedOnAnimationEndListener(
+ inner class DelayedOnAnimationEndListener internal constructor(
private val handler: Handler,
private val runnable: Runnable,
- private val delay: Long
+ private val minDuration: Long
) : DynamicAnimation.OnAnimationEndListener {
-
override fun onAnimationEnd(
animation: DynamicAnimation<*>,
canceled: Boolean,
@@ -203,11 +217,15 @@ class BackPanelController private constructor(
) {
animation.removeEndListener(this)
if (!canceled) {
+ // Total elapsed time of the gesture and the animation
+ val totalElapsedTime = SystemClock.uptimeMillis() - gestureStartTime
+ // The delay between finishing this animation and starting the runnable
+ val delay = max(0, minDuration - totalElapsedTime)
handler.postDelayed(runnable, delay)
}
}
- fun runNow() {
+ internal fun runNow() {
runnable.run()
}
}
@@ -216,7 +234,7 @@ class BackPanelController private constructor(
DelayedOnAnimationEndListener(
mainHandler,
{ updateArrowState(GestureState.COMMITTED) },
- delay = FLING_PAUSE_DURATION_MS
+ minDuration = FLING_MIN_APPEARANCE_DURATION
)
private val setGoneEndListener =
@@ -226,21 +244,21 @@ class BackPanelController private constructor(
cancelFailsafe()
updateArrowState(GestureState.GONE)
},
- delay = 0
+ minDuration = 0
)
// Vibration
private var vibrationTime: Long = 0
- // Minimum size of the screen's width or height
- private var screenSize = 0
+ // Minimum of the screen's width or the predefined threshold
+ private var fullyStretchedThreshold = 0f
/**
* Used for initialization and configuration changes
*/
private fun updateConfiguration() {
params.update(resources)
- initializeBackAnimation()
+ updateBackAnimationSwipeThresholds()
mView.updateArrowPaint(params.arrowThickness)
}
@@ -284,6 +302,7 @@ class BackPanelController private constructor(
resetOnDown()
startX = event.x
startY = event.y
+ gestureStartTime = SystemClock.uptimeMillis()
// Reset the arrow to the side
updateArrowState(GestureState.ENTRY)
@@ -308,40 +327,39 @@ class BackPanelController private constructor(
}
private fun updateArrowStateOnMove(yTranslation: Float, xTranslation: Float) {
+ if (!currentState.isInteractive())
+ return
+
when (currentState) {
- GestureState.GONE, GestureState.FLUNG, GestureState.COMMITTED, GestureState.CANCELLED ->
- return
- }
+ // Check if we should transition from ENTRY to ACTIVE
+ GestureState.ENTRY ->
+ if (xTranslation > params.swipeTriggerThreshold) {
+ updateArrowState(GestureState.ACTIVE)
+ }
- updateArrowState(
- when {
- // Check if we should transition from ENTRY to ACTIVE
- currentState == GestureState.ENTRY && xTranslation > params.swipeTriggerThreshold ->
- GestureState.ACTIVE
-
- // Abort if we had continuous motion toward the edge for a while, OR the direction
- // in Y is bigger than X * 2
- currentState == GestureState.ACTIVE &&
- ((totalTouchDelta < 0 && -totalTouchDelta > params.minDeltaForSwitch) ||
- (yTranslation > xTranslation * 2)) ->
- GestureState.INACTIVE
-
- // Re-activate if we had continuous motion away from the edge for a while
- currentState == GestureState.INACTIVE &&
- (totalTouchDelta > 0 && totalTouchDelta > params.minDeltaForSwitch) ->
- GestureState.ACTIVE
-
- // By default assume the current direction is kept
- else -> currentState
- }
- )
+ // Abort if we had continuous motion toward the edge for a while, OR the direction
+ // in Y is bigger than X * 2
+ GestureState.ACTIVE ->
+ if ((totalTouchDelta < 0 && -totalTouchDelta > params.minDeltaForSwitch) ||
+ (yTranslation > xTranslation * 2)
+ ) {
+ updateArrowState(GestureState.INACTIVE)
+ }
+
+ // Re-activate if we had continuous motion away from the edge for a while
+ GestureState.INACTIVE ->
+ if (totalTouchDelta > 0 && totalTouchDelta > params.minDeltaForSwitch) {
+ updateArrowState(GestureState.ACTIVE)
+ }
+
+ // By default assume the current direction is kept
+ else -> {}
+ }
}
private fun handleMoveEvent(event: MotionEvent) {
- when (currentState) {
- GestureState.GONE, GestureState.FLUNG, GestureState.COMMITTED,
- GestureState.CANCELLED -> return
- }
+ if (!currentState.isInteractive())
+ return
val x = event.x
val y = event.y
@@ -372,24 +390,25 @@ class BackPanelController private constructor(
updateArrowStateOnMove(yTranslation, xTranslation)
when (currentState) {
- GestureState.ACTIVE -> setActiveStretch(fullScreenStretchProgress(xTranslation))
+ GestureState.ACTIVE ->
+ stretchActiveBackIndicator(fullScreenStretchProgress(xTranslation))
GestureState.ENTRY ->
- setEntryStretch(preThresholdStretchProgress(xTranslation))
- GestureState.INACTIVE -> mView.resetStretch()
+ stretchEntryBackIndicator(preThresholdStretchProgress(xTranslation))
+ GestureState.INACTIVE ->
+ mView.resetStretch()
}
// set y translation
setVerticalTranslation(yOffset)
}
- fun setVerticalTranslation(yOffset: Float) {
+ private fun setVerticalTranslation(yOffset: Float) {
val yTranslation = abs(yOffset)
- val maxYOffset = (mView.height / 2) - (params.entryBackgroundHeight / 2)
+ val maxYOffset = (mView.height - params.entryIndicator.backgroundDimens.height) / 2f
val yProgress = saturate(yTranslation / (maxYOffset * RUBBER_BAND_AMOUNT))
mView.animateVertically(
- RUBBER_BAND_INTERPOLATOR.getInterpolation(yProgress) * maxYOffset * sign(
- yOffset
- )
+ RUBBER_BAND_INTERPOLATOR.getInterpolation(yProgress) * maxYOffset *
+ sign(yOffset)
)
}
@@ -397,13 +416,10 @@ class BackPanelController private constructor(
* @return the relative position of the drag from the time after the arrow is activated until
* the arrow is fully stretched (between 0.0 - 1.0f)
*/
- fun fullScreenStretchProgress(xTranslation: Float): Float {
+ private fun fullScreenStretchProgress(xTranslation: Float): Float {
return saturate(
(xTranslation - params.swipeTriggerThreshold) /
- (min(
- params.fullyStretchedThreshold,
- screenSize.toFloat()
- ) - params.swipeTriggerThreshold)
+ (fullyStretchedThreshold - params.swipeTriggerThreshold)
)
}
@@ -411,57 +427,38 @@ class BackPanelController private constructor(
* Tracks the relative position of the drag from the entry until the threshold where the arrow
* activates (between 0.0 - 1.0f)
*/
- fun preThresholdStretchProgress(xTranslation: Float): Float {
+ private fun preThresholdStretchProgress(xTranslation: Float): Float {
return saturate(xTranslation / params.swipeTriggerThreshold)
}
- fun setActiveStretch(progress: Float) {
- val stretch = RUBBER_BAND_INTERPOLATOR.getInterpolation(progress)
+ private fun stretchActiveBackIndicator(progress: Float) {
+ val rubberBandIterpolation = RUBBER_BAND_INTERPOLATOR.getInterpolation(progress)
mView.setStretch(
- arrowLengthStretch = stretch * (params.stretchedArrowLength - params.activeArrowLength),
- arrowHeightStretch = stretch * (params.stretchedArrowHeight - params.activeArrowHeight),
- backgroundWidthStretch =
- stretch * (params.stretchBackgroundWidth - params.activeBackgroundWidth),
- backgroundHeightStretch =
- stretch * (params.stretchBackgroundHeight - params.activeBackgroundHeight),
- backgroundEdgeCornerRadiusStretch =
- stretch * (params.stretchEdgeCorners - params.activeEdgeCorners),
- backgroundDragCornerRadiusStretch =
- stretch * (params.stretchFarCorners - params.activeFarCorners),
- horizontalTranslationStretch = stretch * (params.stretchMargin - params.activeMargin)
+ horizontalTranslationStretchAmount = rubberBandIterpolation,
+ arrowStretchAmount = rubberBandIterpolation,
+ backgroundWidthStretchAmount = DECELERATE_INTERPOLATOR_SLOW.getInterpolation(progress),
+ params.fullyStretchedIndicator
)
}
- fun setEntryStretch(progress: Float) {
- val bgStretch = ACCELERATE_INTERPOLATOR.getInterpolation(progress)
- val arrowStretch = RUBBER_BAND_INTERPOLATOR.getInterpolation(progress)
+ private fun stretchEntryBackIndicator(progress: Float) {
mView.setStretch(
- arrowLengthStretch =
- arrowStretch * (params.activeArrowLength - params.entryArrowLength),
- arrowHeightStretch =
- arrowStretch * (params.activeArrowHeight - params.entryArrowHeight),
- backgroundWidthStretch =
- bgStretch * (params.preThresholdBackgroundWidth - params.entryBackgroundWidth),
- backgroundHeightStretch =
- bgStretch * (params.preThresholdBackgroundHeight - params.entryBackgroundHeight),
- backgroundEdgeCornerRadiusStretch =
- bgStretch * (params.preThresholdEdgeCorners - params.entryEdgeCorners),
- backgroundDragCornerRadiusStretch =
- bgStretch * (params.preThresholdFarCorners - params.entryFarCorners),
- horizontalTranslationStretch =
- bgStretch * (params.preThresholdMargin - params.entryMargin)
+ horizontalTranslationStretchAmount = 0f,
+ arrowStretchAmount = RUBBER_BAND_INTERPOLATOR.getInterpolation(progress),
+ backgroundWidthStretchAmount = DECELERATE_INTERPOLATOR.getInterpolation(progress),
+ params.preThresholdIndicator
)
}
fun setBackAnimation(backAnimation: BackAnimation?) {
this.backAnimation = backAnimation
- initializeBackAnimation()
+ updateBackAnimationSwipeThresholds()
}
- private fun initializeBackAnimation() {
+ private fun updateBackAnimationSwipeThresholds() {
backAnimation?.setSwipeThresholds(
params.swipeTriggerThreshold,
- params.swipeProgressThreshold
+ fullyStretchedThreshold
)
}
@@ -541,79 +538,68 @@ class BackPanelController private constructor(
private fun updateYPosition(touchY: Float) {
var yPosition = touchY - params.fingerOffset
- yPosition = Math.max(yPosition, params.minArrowYPosition.toFloat())
+ yPosition = max(yPosition, params.minArrowYPosition.toFloat())
yPosition -= layoutParams.height / 2.0f
layoutParams.y = constrain(yPosition.toInt(), 0, displaySize.y)
}
override fun setDisplaySize(displaySize: Point) {
this.displaySize.set(displaySize.x, displaySize.y)
- screenSize = Math.min(displaySize.x, displaySize.y)
+ fullyStretchedThreshold = min(displaySize.x.toFloat(), params.swipeProgressThreshold)
+ updateBackAnimationSwipeThresholds()
}
/**
* Updates resting arrow and background size not accounting for stretch
*/
private fun updateRestingArrowDimens(animated: Boolean, currentState: GestureState) {
- mView.updateRestingArrowDimens(
- backgroundWidth =
- when (currentState) {
- GestureState.GONE, GestureState.ENTRY -> params.entryBackgroundWidth
- else -> params.activeBackgroundWidth
- },
- backgroundHeight =
- when (currentState) {
- GestureState.GONE, GestureState.ENTRY -> params.entryBackgroundHeight
- else -> params.activeBackgroundHeight
- },
- backgroundEdgeCornerRadius =
- when (currentState) {
- GestureState.GONE, GestureState.ENTRY, GestureState.INACTIVE ->
- params.entryEdgeCorners
- else ->
- params.activeEdgeCorners
- },
- backgroundDragCornerRadius =
- when (currentState) {
- GestureState.GONE, GestureState.ENTRY -> params.entryFarCorners
- else -> params.activeFarCorners
- },
- arrowLength =
- when (currentState) {
- GestureState.ACTIVE, GestureState.INACTIVE, GestureState.COMMITTED,
- GestureState.FLUNG -> params.activeArrowLength
- GestureState.CANCELLED -> params.cancelledArrowLength
- GestureState.GONE, GestureState.ENTRY -> params.entryArrowLength
- },
- arrowHeight =
- when (currentState) {
- GestureState.ACTIVE, GestureState.INACTIVE, GestureState.COMMITTED,
- GestureState.FLUNG -> params.activeArrowHeight
- GestureState.CANCELLED -> params.cancelledArrowHeight
- GestureState.GONE, GestureState.ENTRY -> params.entryArrowHeight
- },
- horizontalTranslation =
- when (currentState) {
- GestureState.GONE -> -params.activeBackgroundWidth
- // Position the cancelled/committed arrow slightly further off the screen so we
- // do not see part of it bouncing
- GestureState.CANCELLED, GestureState.COMMITTED ->
- -params.activeBackgroundWidth * 1.5f
- GestureState.FLUNG -> params.stretchMargin
- GestureState.ACTIVE -> params.activeMargin
- GestureState.ENTRY, GestureState.INACTIVE -> params.entryMargin
- },
- animate = animated
- )
if (animated) {
when (currentState) {
GestureState.ENTRY, GestureState.ACTIVE, GestureState.FLUNG ->
mView.setArrowStiffness(ARROW_APPEAR_STIFFNESS, ARROW_APPEAR_DAMPING_RATIO)
+ GestureState.CANCELLED -> mView.fadeOut()
else ->
mView.setArrowStiffness(
- ARROW_DISAPPEAR_STIFFNESS, ARROW_DISAPPEAR_DAMPING_RATIO)
+ ARROW_DISAPPEAR_STIFFNESS,
+ ARROW_DISAPPEAR_DAMPING_RATIO
+ )
}
}
+ mView.setRestingDimens(
+ restingParams = EdgePanelParams.BackIndicatorDimens(
+ horizontalTranslation = when (currentState) {
+ GestureState.GONE -> -params.activeIndicator.backgroundDimens.width
+ // Position the committed arrow slightly further off the screen so we do not
+ // see part of it bouncing
+ GestureState.COMMITTED ->
+ -params.activeIndicator.backgroundDimens.width * 1.5f
+ GestureState.FLUNG -> params.fullyStretchedIndicator.horizontalTranslation
+ GestureState.ACTIVE -> params.activeIndicator.horizontalTranslation
+ GestureState.ENTRY, GestureState.INACTIVE, GestureState.CANCELLED ->
+ params.entryIndicator.horizontalTranslation
+ },
+ arrowDimens = when (currentState) {
+ GestureState.ACTIVE, GestureState.INACTIVE,
+ GestureState.COMMITTED, GestureState.FLUNG -> params.activeIndicator.arrowDimens
+ GestureState.CANCELLED -> params.cancelledArrowDimens
+ GestureState.GONE, GestureState.ENTRY -> params.entryIndicator.arrowDimens
+ },
+ backgroundDimens = when (currentState) {
+ GestureState.GONE, GestureState.ENTRY -> params.entryIndicator.backgroundDimens
+ else ->
+ params.activeIndicator.backgroundDimens.copy(
+ edgeCornerRadius =
+ if (currentState == GestureState.INACTIVE ||
+ currentState == GestureState.CANCELLED
+ )
+ params.entryIndicator.backgroundDimens.edgeCornerRadius
+ else
+ params.activeIndicator.backgroundDimens.edgeCornerRadius
+ )
+ }
+ ),
+ animate = animated
+ )
}
/**
@@ -628,7 +614,12 @@ class BackPanelController private constructor(
if (DEBUG) Log.d(TAG, "updateArrowState $currentState -> $newState")
previousState = currentState
currentState = newState
- mView.visibility = if (currentState == GestureState.GONE) View.GONE else View.VISIBLE
+ if (currentState == GestureState.GONE) {
+ mView.cancelAlphaAnimations()
+ mView.visibility = View.GONE
+ } else {
+ mView.visibility = View.VISIBLE
+ }
when (currentState) {
// Transitioning to GONE never animates since the arrow is (presumably) already off the
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt
index 51566b0f8393..a3fb58d5b015 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt
@@ -4,66 +4,36 @@ import android.content.res.Resources
import com.android.systemui.R
data class EdgePanelParams(private var resources: Resources) {
+
+ data class ArrowDimens(
+ val length: Float = 0f,
+ val height: Float = 0f
+ )
+
+ data class BackgroundDimens(
+ val width: Float = 0f,
+ val height: Float = 0f,
+ val edgeCornerRadius: Float = 0f,
+ val farCornerRadius: Float = 0f
+ )
+
+ data class BackIndicatorDimens(
+ val horizontalTranslation: Float = 0f,
+ val arrowDimens: ArrowDimens = ArrowDimens(),
+ val backgroundDimens: BackgroundDimens = BackgroundDimens()
+ )
+
var arrowThickness: Float = 0f
private set
- var entryArrowLength: Float = 0f
- private set
- var entryArrowHeight: Float = 0f
- private set
- var activeArrowLength: Float = 0f
- private set
- var activeArrowHeight: Float = 0f
- private set
- var stretchedArrowLength: Float = 0f
- private set
- var stretchedArrowHeight: Float = 0f
- private set
- var cancelledArrowLength: Float = 0f
- private set
- var cancelledArrowHeight: Float = 0f
- private set
- var entryMargin: Float = 0f
- private set
- var entryBackgroundWidth: Float = 0f
- private set
- var entryBackgroundHeight: Float = 0f
- private set
- var entryEdgeCorners: Float = 0f
- private set
- var entryFarCorners: Float = 0f
- private set
- var preThresholdMargin: Float = 0f
- private set
- var preThresholdBackgroundWidth: Float = 0f
+ var entryIndicator = BackIndicatorDimens()
private set
- var preThresholdBackgroundHeight: Float = 0f
+ var activeIndicator = BackIndicatorDimens()
private set
- var preThresholdEdgeCorners: Float = 0f
+ var preThresholdIndicator = BackIndicatorDimens()
private set
- var preThresholdFarCorners: Float = 0f
- private set
- var activeMargin: Float = 0f
- private set
- var activeBackgroundWidth: Float = 0f
- private set
- var activeBackgroundHeight: Float = 0f
- private set
- var activeEdgeCorners: Float = 0f
- private set
- var activeFarCorners: Float = 0f
- private set
- var fullyStretchedThreshold: Float = 0f
- private set
- var stretchMargin: Float = 0f
- private set
- var stretchBackgroundWidth: Float = 0f
- private set
- var stretchBackgroundHeight: Float = 0f
- private set
- var stretchEdgeCorners: Float = 0f
- private set
- var stretchFarCorners: Float = 0f
+ var fullyStretchedIndicator = BackIndicatorDimens()
private set
+ var cancelledArrowDimens = ArrowDimens()
// navigation bar edge constants
var arrowPaddingEnd: Int = 0
@@ -98,42 +68,73 @@ data class EdgePanelParams(private var resources: Resources) {
fun update(resources: Resources) {
this.resources = resources
arrowThickness = getDimen(R.dimen.navigation_edge_arrow_thickness)
- entryArrowLength = getDimen(R.dimen.navigation_edge_entry_arrow_length)
- entryArrowHeight = getDimen(R.dimen.navigation_edge_entry_arrow_height)
- activeArrowLength = getDimen(R.dimen.navigation_edge_active_arrow_length)
- activeArrowHeight = getDimen(R.dimen.navigation_edge_active_arrow_height)
- stretchedArrowLength = getDimen(R.dimen.navigation_edge_stretched_arrow_length)
- stretchedArrowHeight = getDimen(R.dimen.navigation_edge_stretched_arrow_height)
- cancelledArrowLength = getDimen(R.dimen.navigation_edge_cancelled_arrow_length)
- cancelledArrowHeight = getDimen(R.dimen.navigation_edge_cancelled_arrow_height)
- entryMargin = getDimen(R.dimen.navigation_edge_entry_margin)
- entryBackgroundWidth = getDimen(R.dimen.navigation_edge_entry_background_width)
- entryBackgroundHeight = getDimen(R.dimen.navigation_edge_entry_background_height)
- entryEdgeCorners = getDimen(R.dimen.navigation_edge_entry_edge_corners)
- entryFarCorners = getDimen(R.dimen.navigation_edge_entry_far_corners)
- preThresholdMargin = getDimen(R.dimen.navigation_edge_pre_threshold_margin)
- preThresholdBackgroundWidth =
- getDimen(R.dimen.navigation_edge_pre_threshold_background_width)
- preThresholdBackgroundHeight =
- getDimen(R.dimen.navigation_edge_pre_threshold_background_height)
- preThresholdEdgeCorners = getDimen(R.dimen.navigation_edge_pre_threshold_edge_corners)
- preThresholdFarCorners = getDimen(R.dimen.navigation_edge_pre_threshold_far_corners)
- activeMargin = getDimen(R.dimen.navigation_edge_active_margin)
- activeBackgroundWidth = getDimen(R.dimen.navigation_edge_active_background_width)
- activeBackgroundHeight = getDimen(R.dimen.navigation_edge_active_background_height)
- activeEdgeCorners = getDimen(R.dimen.navigation_edge_active_edge_corners)
- activeFarCorners = getDimen(R.dimen.navigation_edge_active_far_corners)
- fullyStretchedThreshold = getDimen(R.dimen.navigation_edge_stretch_threshold)
- stretchMargin = getDimen(R.dimen.navigation_edge_stretch_margin)
- stretchBackgroundWidth = getDimen(R.dimen.navigation_edge_stretch_background_width)
- stretchBackgroundHeight = getDimen(R.dimen.navigation_edge_stretch_background_height)
- stretchEdgeCorners = getDimen(R.dimen.navigation_edge_stretch_left_corners)
- stretchFarCorners = getDimen(R.dimen.navigation_edge_stretch_right_corners)
arrowPaddingEnd = getPx(R.dimen.navigation_edge_panel_padding)
minArrowYPosition = getPx(R.dimen.navigation_edge_arrow_min_y)
fingerOffset = getPx(R.dimen.navigation_edge_finger_offset)
swipeTriggerThreshold = getDimen(R.dimen.navigation_edge_action_drag_threshold)
swipeProgressThreshold = getDimen(R.dimen.navigation_edge_action_progress_threshold)
minDeltaForSwitch = getPx(R.dimen.navigation_edge_minimum_x_delta_for_switch)
+
+ entryIndicator = BackIndicatorDimens(
+ horizontalTranslation = getDimen(R.dimen.navigation_edge_entry_margin),
+ arrowDimens = ArrowDimens(
+ length = getDimen(R.dimen.navigation_edge_entry_arrow_length),
+ height = getDimen(R.dimen.navigation_edge_entry_arrow_height),
+ ),
+ backgroundDimens = BackgroundDimens(
+ width = getDimen(R.dimen.navigation_edge_entry_background_width),
+ height = getDimen(R.dimen.navigation_edge_entry_background_height),
+ edgeCornerRadius = getDimen(R.dimen.navigation_edge_entry_edge_corners),
+ farCornerRadius = getDimen(R.dimen.navigation_edge_entry_far_corners)
+ )
+ )
+
+ activeIndicator = BackIndicatorDimens(
+ horizontalTranslation = getDimen(R.dimen.navigation_edge_active_margin),
+ arrowDimens = ArrowDimens(
+ length = getDimen(R.dimen.navigation_edge_active_arrow_length),
+ height = getDimen(R.dimen.navigation_edge_active_arrow_height),
+ ),
+ backgroundDimens = BackgroundDimens(
+ width = getDimen(R.dimen.navigation_edge_active_background_width),
+ height = getDimen(R.dimen.navigation_edge_active_background_height),
+ edgeCornerRadius = getDimen(R.dimen.navigation_edge_active_edge_corners),
+ farCornerRadius = getDimen(R.dimen.navigation_edge_active_far_corners)
+
+ )
+ )
+
+ preThresholdIndicator = BackIndicatorDimens(
+ horizontalTranslation = getDimen(R.dimen.navigation_edge_pre_threshold_margin),
+ arrowDimens = ArrowDimens(
+ length = entryIndicator.arrowDimens.length,
+ height = entryIndicator.arrowDimens.height,
+ ),
+ backgroundDimens = BackgroundDimens(
+ width = getDimen(R.dimen.navigation_edge_pre_threshold_background_width),
+ height = getDimen(R.dimen.navigation_edge_pre_threshold_background_height),
+ edgeCornerRadius = getDimen(R.dimen.navigation_edge_pre_threshold_edge_corners),
+ farCornerRadius = getDimen(R.dimen.navigation_edge_pre_threshold_far_corners)
+ )
+ )
+
+ fullyStretchedIndicator = BackIndicatorDimens(
+ horizontalTranslation = getDimen(R.dimen.navigation_edge_stretch_margin),
+ arrowDimens = ArrowDimens(
+ length = getDimen(R.dimen.navigation_edge_stretched_arrow_length),
+ height = getDimen(R.dimen.navigation_edge_stretched_arrow_height),
+ ),
+ backgroundDimens = BackgroundDimens(
+ width = getDimen(R.dimen.navigation_edge_stretch_background_width),
+ height = getDimen(R.dimen.navigation_edge_stretch_background_height),
+ edgeCornerRadius = getDimen(R.dimen.navigation_edge_stretch_edge_corners),
+ farCornerRadius = getDimen(R.dimen.navigation_edge_stretch_far_corners)
+ )
+ )
+
+ cancelledArrowDimens = ArrowDimens(
+ length = getDimen(R.dimen.navigation_edge_cancelled_arrow_length),
+ height = getDimen(R.dimen.navigation_edge_cancelled_arrow_height)
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
index 1a7bd8cb6cf9..18be0aa6580d 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -289,7 +289,7 @@ public class PeopleSpaceWidgetManager {
if (DEBUG) Log.d(TAG, "Updating widget: " + appWidgetId);
PeopleSpaceTile tile = getTileForExistingWidget(appWidgetId);
if (tile == null) {
- Log.e(TAG, "Matching conversation not found for shortcut ID");
+ Log.e(TAG, "Matching conversation not found for widget " + appWidgetId);
}
updateAppWidgetOptionsAndView(appWidgetId, tile);
widgetIdToTile.put(appWidgetId, tile);
@@ -308,7 +308,7 @@ public class PeopleSpaceWidgetManager {
if (DEBUG) Log.d(TAG, "Widget: " + appWidgetId + " for: " + key.toString());
if (!PeopleTileKey.isValid(key)) {
- Log.e(TAG, "Cannot update invalid widget");
+ Log.e(TAG, "Invalid tile key updating widget " + appWidgetId);
return;
}
RemoteViews views = PeopleTileViewHelper.createRemoteViews(mContext, tile, appWidgetId,
@@ -330,7 +330,7 @@ public class PeopleSpaceWidgetManager {
/** Updates tile in app widget options and the current view. */
public void updateAppWidgetOptionsAndView(int appWidgetId, PeopleSpaceTile tile) {
if (tile == null) {
- if (DEBUG) Log.w(TAG, "Storing null tile");
+ Log.w(TAG, "Storing null tile for widget " + appWidgetId);
}
synchronized (mTiles) {
mTiles.put(appWidgetId, tile);
@@ -348,7 +348,7 @@ public class PeopleSpaceWidgetManager {
try {
return getTileForExistingWidgetThrowing(appWidgetId);
} catch (Exception e) {
- Log.e(TAG, "failed to retrieve tile for widget ID " + appWidgetId, e);
+ Log.e(TAG, "failed to retrieve tile for existing widget " + appWidgetId, e);
return null;
}
}
@@ -388,7 +388,7 @@ public class PeopleSpaceWidgetManager {
boolean supplementFromStorage) throws
PackageManager.NameNotFoundException {
if (!PeopleTileKey.isValid(key)) {
- Log.e(TAG, "PeopleTileKey invalid: " + key.toString());
+ Log.e(TAG, "Invalid tile key finding tile for existing widget " + appWidgetId);
return null;
}
@@ -423,7 +423,7 @@ public class PeopleSpaceWidgetManager {
// Add current state.
return getTileWithCurrentState(storedTile.build(), ACTION_BOOT_COMPLETED);
} catch (RemoteException e) {
- Log.e(TAG, "getTileFromPersistentStorage failing", e);
+ Log.e(TAG, "getTileFromPersistentStorage failing for widget " + appWidgetId, e);
return null;
}
}
@@ -591,10 +591,7 @@ public class PeopleSpaceWidgetManager {
if (DEBUG) Log.d(TAG, "Augmenting tile for existing widget: " + widgetId);
PeopleSpaceTile tile = getTileForExistingWidget(widgetId);
if (tile == null) {
- if (DEBUG) {
- Log.w(TAG, "Widget: " + widgetId
- + ". Null tile for existing widget, skipping update.");
- }
+ Log.w(TAG, "Null tile for existing widget " + widgetId + ", skipping update.");
return Optional.empty();
}
String contactUriString = mSharedPrefs.getString(String.valueOf(widgetId), null);
@@ -816,7 +813,7 @@ public class PeopleSpaceWidgetManager {
tile = getTileFromPersistentStorage(key, appWidgetId, /* supplementFromStorage= */
false);
} catch (PackageManager.NameNotFoundException e) {
- Log.e(TAG, "Cannot add widget since app was uninstalled");
+ Log.e(TAG, "Cannot add widget " + appWidgetId + " since app was uninstalled");
return;
}
if (tile == null) {
@@ -851,7 +848,7 @@ public class PeopleSpaceWidgetManager {
Collections.singletonList(tile.getId()),
tile.getUserHandle(), LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS);
} catch (Exception e) {
- Log.w(TAG, "failed to cache shortcut", e);
+ Log.w(TAG, "failed to cache shortcut for widget " + appWidgetId, e);
}
PeopleSpaceTile finalTile = tile;
mBgExecutor.execute(
@@ -862,7 +859,7 @@ public class PeopleSpaceWidgetManager {
public void registerConversationListenerIfNeeded(int widgetId, PeopleTileKey key) {
// Retrieve storage needed for registration.
if (!PeopleTileKey.isValid(key)) {
- if (DEBUG) Log.w(TAG, "Could not register listener for widget: " + widgetId);
+ Log.w(TAG, "Invalid tile key registering listener for widget " + widgetId);
return;
}
TileConversationListener newListener = new TileConversationListener();
@@ -911,7 +908,7 @@ public class PeopleSpaceWidgetManager {
widgetSp.getInt(USER_ID, INVALID_USER_ID),
widgetSp.getString(PACKAGE_NAME, null));
if (!PeopleTileKey.isValid(key)) {
- if (DEBUG) Log.e(TAG, "Could not delete " + widgetId);
+ Log.e(TAG, "Invalid tile key trying to remove widget " + widgetId);
return;
}
storedWidgetIdsForKey = new HashSet<>(
@@ -1083,7 +1080,8 @@ public class PeopleSpaceWidgetManager {
synchronized (mLock) {
existingTile = getTileForExistingWidgetThrowing(appWidgetId);
if (existingTile == null) {
- Log.e(TAG, "Matching conversation not found for shortcut ID");
+ Log.e(TAG, "Matching conversation not found for widget "
+ + appWidgetId);
continue;
}
updatedTile = getTileWithCurrentState(existingTile, entryPoint);
@@ -1091,7 +1089,7 @@ public class PeopleSpaceWidgetManager {
}
} catch (PackageManager.NameNotFoundException e) {
// Delete data for uninstalled widgets.
- Log.e(TAG, "package no longer found for tile", e);
+ Log.e(TAG, "Package no longer found for widget " + appWidgetId, e);
JobScheduler jobScheduler = mContext.getSystemService(JobScheduler.class);
if (jobScheduler != null
&& jobScheduler.getPendingJob(PeopleBackupFollowUpJob.JOB_ID) != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitor.kt b/packages/SystemUI/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitor.kt
new file mode 100644
index 000000000000..de34cd6b23ca
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitor.kt
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.privacy
+
+import android.app.AppOpsManager
+import android.content.Context
+import android.content.pm.UserInfo
+import android.os.UserHandle
+import com.android.internal.annotations.GuardedBy
+import com.android.internal.annotations.VisibleForTesting
+import com.android.systemui.appops.AppOpItem
+import com.android.systemui.appops.AppOpsController
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.privacy.logging.PrivacyLogger
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.util.asIndenting
+import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.withIncreasedIndent
+import java.io.PrintWriter
+import javax.inject.Inject
+
+/**
+ * Monitors privacy items backed by app ops:
+ * - Mic & Camera
+ * - Location
+ *
+ * If [PrivacyConfig.micCameraAvailable] / [PrivacyConfig.locationAvailable] are disabled,
+ * the corresponding PrivacyItems will not be reported.
+ */
+@SysUISingleton
+class AppOpsPrivacyItemMonitor @Inject constructor(
+ private val appOpsController: AppOpsController,
+ private val userTracker: UserTracker,
+ private val privacyConfig: PrivacyConfig,
+ @Background private val bgExecutor: DelayableExecutor,
+ private val logger: PrivacyLogger
+) : PrivacyItemMonitor {
+
+ @VisibleForTesting
+ companion object {
+ val OPS_MIC_CAMERA = intArrayOf(AppOpsManager.OP_CAMERA,
+ AppOpsManager.OP_PHONE_CALL_CAMERA, AppOpsManager.OP_RECORD_AUDIO,
+ AppOpsManager.OP_PHONE_CALL_MICROPHONE,
+ AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO)
+ val OPS_LOCATION = intArrayOf(
+ AppOpsManager.OP_COARSE_LOCATION,
+ AppOpsManager.OP_FINE_LOCATION)
+ val OPS = OPS_MIC_CAMERA + OPS_LOCATION
+ val USER_INDEPENDENT_OPS = intArrayOf(AppOpsManager.OP_PHONE_CALL_CAMERA,
+ AppOpsManager.OP_PHONE_CALL_MICROPHONE)
+ }
+
+ private val lock = Any()
+
+ @GuardedBy("lock")
+ private var callback: PrivacyItemMonitor.Callback? = null
+ @GuardedBy("lock")
+ private var micCameraAvailable = privacyConfig.micCameraAvailable
+ @GuardedBy("lock")
+ private var locationAvailable = privacyConfig.locationAvailable
+ @GuardedBy("lock")
+ private var listening = false
+
+ private val appOpsCallback = object : AppOpsController.Callback {
+ override fun onActiveStateChanged(
+ code: Int,
+ uid: Int,
+ packageName: String,
+ active: Boolean
+ ) {
+ synchronized(lock) {
+ // Check if we care about this code right now
+ if (code in OPS_MIC_CAMERA && !micCameraAvailable) {
+ return
+ }
+ if (code in OPS_LOCATION && !locationAvailable) {
+ return
+ }
+ if (userTracker.userProfiles.any { it.id == UserHandle.getUserId(uid) } ||
+ code in USER_INDEPENDENT_OPS) {
+ logger.logUpdatedItemFromAppOps(code, uid, packageName, active)
+ dispatchOnPrivacyItemsChanged()
+ }
+ }
+ }
+ }
+
+ @VisibleForTesting
+ internal val userTrackerCallback = object : UserTracker.Callback {
+ override fun onUserChanged(newUser: Int, userContext: Context) {
+ onCurrentProfilesChanged()
+ }
+
+ override fun onProfilesChanged(profiles: List<UserInfo>) {
+ onCurrentProfilesChanged()
+ }
+ }
+
+ private val configCallback = object : PrivacyConfig.Callback {
+ override fun onFlagLocationChanged(flag: Boolean) {
+ onFlagChanged()
+ }
+
+ override fun onFlagMicCameraChanged(flag: Boolean) {
+ onFlagChanged()
+ }
+
+ private fun onFlagChanged() {
+ synchronized(lock) {
+ micCameraAvailable = privacyConfig.micCameraAvailable
+ locationAvailable = privacyConfig.locationAvailable
+ setListeningStateLocked()
+ }
+ dispatchOnPrivacyItemsChanged()
+ }
+ }
+
+ init {
+ privacyConfig.addCallback(configCallback)
+ }
+
+ override fun startListening(callback: PrivacyItemMonitor.Callback) {
+ synchronized(lock) {
+ this.callback = callback
+ setListeningStateLocked()
+ }
+ }
+
+ override fun stopListening() {
+ synchronized(lock) {
+ this.callback = null
+ setListeningStateLocked()
+ }
+ }
+
+ /**
+ * Updates listening status based on whether there are callbacks and the indicators are enabled.
+ *
+ * Always listen to all OPS so we don't have to figure out what we should be listening to. We
+ * still have to filter anyway. Updates are filtered in the callback.
+ *
+ * This is only called from private (add/remove)Callback and from the config listener, all in
+ * main thread.
+ */
+ @GuardedBy("lock")
+ private fun setListeningStateLocked() {
+ val shouldListen = callback != null && (micCameraAvailable || locationAvailable)
+ if (listening == shouldListen) {
+ return
+ }
+
+ listening = shouldListen
+ if (shouldListen) {
+ appOpsController.addCallback(OPS, appOpsCallback)
+ userTracker.addCallback(userTrackerCallback, bgExecutor)
+ onCurrentProfilesChanged()
+ } else {
+ appOpsController.removeCallback(OPS, appOpsCallback)
+ userTracker.removeCallback(userTrackerCallback)
+ }
+ }
+
+ override fun getActivePrivacyItems(): List<PrivacyItem> {
+ val activeAppOps = appOpsController.getActiveAppOps(true)
+ val currentUserProfiles = userTracker.userProfiles
+
+ return synchronized(lock) {
+ activeAppOps.filter {
+ currentUserProfiles.any { user -> user.id == UserHandle.getUserId(it.uid) } ||
+ it.code in USER_INDEPENDENT_OPS
+ }.mapNotNull { toPrivacyItemLocked(it) }
+ }.distinct()
+ }
+
+ @GuardedBy("lock")
+ private fun privacyItemForAppOpEnabledLocked(code: Int): Boolean {
+ if (code in OPS_LOCATION) {
+ return locationAvailable
+ } else if (code in OPS_MIC_CAMERA) {
+ return micCameraAvailable
+ } else {
+ return false
+ }
+ }
+
+ @GuardedBy("lock")
+ private fun toPrivacyItemLocked(appOpItem: AppOpItem): PrivacyItem? {
+ if (!privacyItemForAppOpEnabledLocked(appOpItem.code)) {
+ return null
+ }
+ val type: PrivacyType = when (appOpItem.code) {
+ AppOpsManager.OP_PHONE_CALL_CAMERA,
+ AppOpsManager.OP_CAMERA -> PrivacyType.TYPE_CAMERA
+ AppOpsManager.OP_COARSE_LOCATION,
+ AppOpsManager.OP_FINE_LOCATION -> PrivacyType.TYPE_LOCATION
+ AppOpsManager.OP_PHONE_CALL_MICROPHONE,
+ AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO,
+ AppOpsManager.OP_RECORD_AUDIO -> PrivacyType.TYPE_MICROPHONE
+ else -> return null
+ }
+ val app = PrivacyApplication(appOpItem.packageName, appOpItem.uid)
+ return PrivacyItem(type, app, appOpItem.timeStartedElapsed, appOpItem.isDisabled)
+ }
+
+ private fun onCurrentProfilesChanged() {
+ val currentUserIds = userTracker.userProfiles.map { it.id }
+ logger.logCurrentProfilesChanged(currentUserIds)
+ dispatchOnPrivacyItemsChanged()
+ }
+
+ private fun dispatchOnPrivacyItemsChanged() {
+ val cb = synchronized(lock) { callback }
+ if (cb != null) {
+ bgExecutor.execute {
+ cb.onPrivacyItemsChanged()
+ }
+ }
+ }
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ val ipw = pw.asIndenting()
+ ipw.println("AppOpsPrivacyItemMonitor:")
+ ipw.withIncreasedIndent {
+ synchronized(lock) {
+ ipw.println("Listening: $listening")
+ ipw.println("micCameraAvailable: $micCameraAvailable")
+ ipw.println("locationAvailable: $locationAvailable")
+ ipw.println("Callback: $callback")
+ }
+ ipw.println("Current user ids: ${userTracker.userProfiles.map { it.id }}")
+ }
+ ipw.flush()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/MediaProjectionPrivacyItemMonitor.kt b/packages/SystemUI/src/com/android/systemui/privacy/MediaProjectionPrivacyItemMonitor.kt
new file mode 100644
index 000000000000..9b5a675371cc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/privacy/MediaProjectionPrivacyItemMonitor.kt
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.privacy
+
+import android.content.pm.PackageManager
+import android.media.projection.MediaProjectionInfo
+import android.media.projection.MediaProjectionManager
+import android.os.Handler
+import android.util.Log
+import androidx.annotation.WorkerThread
+import com.android.internal.annotations.GuardedBy
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.privacy.logging.PrivacyLogger
+import com.android.systemui.util.asIndenting
+import com.android.systemui.util.time.SystemClock
+import com.android.systemui.util.withIncreasedIndent
+import java.io.PrintWriter
+import javax.inject.Inject
+
+/**
+ * Monitors the active media projection to update privacy items.
+ */
+@SysUISingleton
+class MediaProjectionPrivacyItemMonitor @Inject constructor(
+ private val mediaProjectionManager: MediaProjectionManager,
+ private val packageManager: PackageManager,
+ private val privacyConfig: PrivacyConfig,
+ @Background private val bgHandler: Handler,
+ private val systemClock: SystemClock,
+ private val logger: PrivacyLogger
+) : PrivacyItemMonitor {
+
+ companion object {
+ const val TAG = "MediaProjectionPrivacyItemMonitor"
+ const val DEBUG = false
+ }
+
+ private val lock = Any()
+
+ @GuardedBy("lock")
+ private var callback: PrivacyItemMonitor.Callback? = null
+
+ @GuardedBy("lock")
+ private var mediaProjectionAvailable = privacyConfig.mediaProjectionAvailable
+ @GuardedBy("lock")
+ private var listening = false
+
+ @GuardedBy("lock")
+ private val privacyItems = mutableListOf<PrivacyItem>()
+
+ private val optionsCallback = object : PrivacyConfig.Callback {
+ override fun onFlagMediaProjectionChanged(flag: Boolean) {
+ synchronized(lock) {
+ mediaProjectionAvailable = privacyConfig.mediaProjectionAvailable
+ setListeningStateLocked()
+ }
+ dispatchOnPrivacyItemsChanged()
+ }
+ }
+
+ private val mediaProjectionCallback = object : MediaProjectionManager.Callback() {
+ @WorkerThread
+ override fun onStart(info: MediaProjectionInfo) {
+ synchronized(lock) { onMediaProjectionStartedLocked(info) }
+ dispatchOnPrivacyItemsChanged()
+ }
+
+ @WorkerThread
+ override fun onStop(info: MediaProjectionInfo) {
+ synchronized(lock) { onMediaProjectionStoppedLocked(info) }
+ dispatchOnPrivacyItemsChanged()
+ }
+ }
+
+ init {
+ privacyConfig.addCallback(optionsCallback)
+ setListeningStateLocked()
+ }
+
+ override fun startListening(callback: PrivacyItemMonitor.Callback) {
+ synchronized(lock) {
+ this.callback = callback
+ }
+ }
+
+ override fun stopListening() {
+ synchronized(lock) {
+ this.callback = null
+ }
+ }
+
+ @GuardedBy("lock")
+ @WorkerThread
+ private fun onMediaProjectionStartedLocked(info: MediaProjectionInfo) {
+ if (DEBUG) Log.d(TAG, "onMediaProjectionStartedLocked: info=$info")
+ val item = makePrivacyItem(info)
+ privacyItems.add(item)
+ logItemActive(item, true)
+ }
+
+ @GuardedBy("lock")
+ @WorkerThread
+ private fun onMediaProjectionStoppedLocked(info: MediaProjectionInfo) {
+ if (DEBUG) Log.d(TAG, "onMediaProjectionStoppedLocked: info=$info")
+ val item = makePrivacyItem(info)
+ privacyItems.removeAt(privacyItems.indexOfFirst { it.application == item.application })
+ logItemActive(item, false)
+ }
+
+ @WorkerThread
+ private fun makePrivacyItem(info: MediaProjectionInfo): PrivacyItem {
+ val userId = info.userHandle.identifier
+ val uid = packageManager.getPackageUidAsUser(info.packageName, userId)
+ val app = PrivacyApplication(info.packageName, uid)
+ val now = systemClock.elapsedRealtime()
+ return PrivacyItem(PrivacyType.TYPE_MEDIA_PROJECTION, app, now)
+ }
+
+ private fun logItemActive(item: PrivacyItem, active: Boolean) {
+ logger.logUpdatedItemFromMediaProjection(
+ item.application.uid, item.application.packageName, active)
+ }
+
+ /**
+ * Updates listening status based on whether there are callbacks and the indicator is enabled.
+ */
+ @GuardedBy("lock")
+ private fun setListeningStateLocked() {
+ val shouldListen = mediaProjectionAvailable
+ if (DEBUG) {
+ Log.d(TAG, "shouldListen=$shouldListen, " +
+ "mediaProjectionAvailable=$mediaProjectionAvailable")
+ }
+ if (listening == shouldListen) {
+ return
+ }
+
+ listening = shouldListen
+ if (shouldListen) {
+ if (DEBUG) Log.d(TAG, "Registering MediaProjectionManager callback")
+ mediaProjectionManager.addCallback(mediaProjectionCallback, bgHandler)
+
+ val activeProjection = mediaProjectionManager.activeProjectionInfo
+ if (activeProjection != null) {
+ onMediaProjectionStartedLocked(activeProjection)
+ dispatchOnPrivacyItemsChanged()
+ }
+ } else {
+ if (DEBUG) Log.d(TAG, "Unregistering MediaProjectionManager callback")
+ mediaProjectionManager.removeCallback(mediaProjectionCallback)
+ privacyItems.forEach { logItemActive(it, false) }
+ privacyItems.clear()
+ dispatchOnPrivacyItemsChanged()
+ }
+ }
+
+ override fun getActivePrivacyItems(): List<PrivacyItem> {
+ synchronized(lock) {
+ if (DEBUG) Log.d(TAG, "getActivePrivacyItems: privacyItems=$privacyItems")
+ return privacyItems.toList()
+ }
+ }
+
+ private fun dispatchOnPrivacyItemsChanged() {
+ if (DEBUG) Log.d(TAG, "dispatchOnPrivacyItemsChanged")
+ val cb = synchronized(lock) { callback }
+ if (cb != null) {
+ bgHandler.post {
+ cb.onPrivacyItemsChanged()
+ }
+ }
+ }
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ val ipw = pw.asIndenting()
+ ipw.println("MediaProjectionPrivacyItemMonitor:")
+ ipw.withIncreasedIndent {
+ synchronized(lock) {
+ ipw.println("Listening: $listening")
+ ipw.println("mediaProjectionAvailable: $mediaProjectionAvailable")
+ ipw.println("Callback: $callback")
+ ipw.println("Privacy Items: $privacyItems")
+ }
+ }
+ ipw.flush()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyConfig.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyConfig.kt
new file mode 100644
index 000000000000..d652889f0082
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyConfig.kt
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.privacy
+
+import android.provider.DeviceConfig
+import com.android.internal.annotations.VisibleForTesting
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags
+import com.android.systemui.Dumpable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.util.DeviceConfigProxy
+import com.android.systemui.util.asIndenting
+import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.withIncreasedIndent
+import java.io.PrintWriter
+import java.lang.ref.WeakReference
+import javax.inject.Inject
+
+@SysUISingleton
+class PrivacyConfig @Inject constructor(
+ @Main private val uiExecutor: DelayableExecutor,
+ private val deviceConfigProxy: DeviceConfigProxy,
+ dumpManager: DumpManager
+) : Dumpable {
+
+ @VisibleForTesting
+ internal companion object {
+ const val TAG = "PrivacyConfig"
+ private const val MIC_CAMERA = SystemUiDeviceConfigFlags.PROPERTY_MIC_CAMERA_ENABLED
+ private const val LOCATION = SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_ENABLED
+ private const val MEDIA_PROJECTION =
+ SystemUiDeviceConfigFlags.PROPERTY_MEDIA_PROJECTION_INDICATORS_ENABLED
+ private const val DEFAULT_MIC_CAMERA = true
+ private const val DEFAULT_LOCATION = false
+ private const val DEFAULT_MEDIA_PROJECTION = true
+ }
+
+ private val callbacks = mutableListOf<WeakReference<Callback>>()
+
+ var micCameraAvailable = isMicCameraEnabled()
+ private set
+ var locationAvailable = isLocationEnabled()
+ private set
+ var mediaProjectionAvailable = isMediaProjectionEnabled()
+ private set
+
+ private val devicePropertiesChangedListener =
+ DeviceConfig.OnPropertiesChangedListener { properties ->
+ if (DeviceConfig.NAMESPACE_PRIVACY == properties.namespace) {
+ // Running on the ui executor so can iterate on callbacks
+ if (properties.keyset.contains(MIC_CAMERA)) {
+ micCameraAvailable = properties.getBoolean(MIC_CAMERA, DEFAULT_MIC_CAMERA)
+ callbacks.forEach { it.get()?.onFlagMicCameraChanged(micCameraAvailable) }
+ }
+
+ if (properties.keyset.contains(LOCATION)) {
+ locationAvailable = properties.getBoolean(LOCATION, DEFAULT_LOCATION)
+ callbacks.forEach { it.get()?.onFlagLocationChanged(locationAvailable) }
+ }
+
+ if (properties.keyset.contains(MEDIA_PROJECTION)) {
+ mediaProjectionAvailable =
+ properties.getBoolean(MEDIA_PROJECTION, DEFAULT_MEDIA_PROJECTION)
+ callbacks.forEach {
+ it.get()?.onFlagMediaProjectionChanged(mediaProjectionAvailable)
+ }
+ }
+ }
+ }
+
+ init {
+ dumpManager.registerDumpable(TAG, this)
+ deviceConfigProxy.addOnPropertiesChangedListener(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ uiExecutor,
+ devicePropertiesChangedListener)
+ }
+
+ private fun isMicCameraEnabled(): Boolean {
+ return deviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+ MIC_CAMERA, DEFAULT_MIC_CAMERA)
+ }
+
+ private fun isLocationEnabled(): Boolean {
+ return deviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+ LOCATION, DEFAULT_LOCATION)
+ }
+
+ private fun isMediaProjectionEnabled(): Boolean {
+ return deviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+ MEDIA_PROJECTION, DEFAULT_MEDIA_PROJECTION)
+ }
+
+ fun addCallback(callback: Callback) {
+ addCallback(WeakReference(callback))
+ }
+
+ fun removeCallback(callback: Callback) {
+ removeCallback(WeakReference(callback))
+ }
+
+ private fun addCallback(callback: WeakReference<Callback>) {
+ uiExecutor.execute {
+ callbacks.add(callback)
+ }
+ }
+
+ private fun removeCallback(callback: WeakReference<Callback>) {
+ uiExecutor.execute {
+ // Removes also if the callback is null
+ callbacks.removeIf { it.get()?.equals(callback.get()) ?: true }
+ }
+ }
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ val ipw = pw.asIndenting()
+ ipw.println("PrivacyConfig state:")
+ ipw.withIncreasedIndent {
+ ipw.println("micCameraAvailable: $micCameraAvailable")
+ ipw.println("locationAvailable: $locationAvailable")
+ ipw.println("mediaProjectionAvailable: $mediaProjectionAvailable")
+ ipw.println("Callbacks:")
+ ipw.withIncreasedIndent {
+ callbacks.forEach { callback ->
+ callback.get()?.let { ipw.println(it) }
+ }
+ }
+ }
+ ipw.flush()
+ }
+
+ interface Callback {
+ @JvmDefault
+ fun onFlagMicCameraChanged(flag: Boolean) {}
+
+ @JvmDefault
+ fun onFlagLocationChanged(flag: Boolean) {}
+
+ @JvmDefault
+ fun onFlagMediaProjectionChanged(flag: Boolean) {}
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
index d4e164208167..03145a714289 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
@@ -165,6 +165,7 @@ class PrivacyDialog(
PrivacyType.TYPE_LOCATION -> R.drawable.privacy_item_circle_location
PrivacyType.TYPE_CAMERA -> R.drawable.privacy_item_circle_camera
PrivacyType.TYPE_MICROPHONE -> R.drawable.privacy_item_circle_microphone
+ PrivacyType.TYPE_MEDIA_PROJECTION -> R.drawable.privacy_item_circle_media_projection
}) as LayerDrawable
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
index 76199bfab0e0..8b41000d2543 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
@@ -43,6 +43,12 @@ enum class PrivacyType(
com.android.internal.R.drawable.perm_group_location,
android.Manifest.permission_group.LOCATION,
"location"
+ ),
+ TYPE_MEDIA_PROJECTION(
+ R.string.privacy_type_media_projection,
+ R.drawable.stat_sys_cast,
+ android.Manifest.permission_group.UNDEFINED,
+ "media projection"
);
fun getName(context: Context) = context.resources.getString(nameId)
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index cd6eb99e259e..a676150f44a2 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -16,27 +16,18 @@
package com.android.systemui.privacy
-import android.app.AppOpsManager
-import android.content.Context
-import android.content.Intent
-import android.content.IntentFilter
-import android.content.pm.UserInfo
-import android.os.UserHandle
-import android.provider.DeviceConfig
import com.android.internal.annotations.VisibleForTesting
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags
import com.android.systemui.Dumpable
-import com.android.systemui.appops.AppOpItem
import com.android.systemui.appops.AppOpsController
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.privacy.logging.PrivacyLogger
-import com.android.systemui.settings.UserTracker
-import com.android.systemui.util.DeviceConfigProxy
+import com.android.systemui.util.asIndenting
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.time.SystemClock
+import com.android.systemui.util.withIncreasedIndent
import java.io.PrintWriter
import java.lang.ref.WeakReference
import java.util.concurrent.Executor
@@ -44,11 +35,10 @@ import javax.inject.Inject
@SysUISingleton
class PrivacyItemController @Inject constructor(
- private val appOpsController: AppOpsController,
@Main uiExecutor: DelayableExecutor,
@Background private val bgExecutor: DelayableExecutor,
- private val deviceConfigProxy: DeviceConfigProxy,
- private val userTracker: UserTracker,
+ private val privacyConfig: PrivacyConfig,
+ private val privacyItemMonitors: Set<@JvmSuppressWildcards PrivacyItemMonitor>,
private val logger: PrivacyLogger,
private val systemClock: SystemClock,
dumpManager: DumpManager
@@ -56,24 +46,7 @@ class PrivacyItemController @Inject constructor(
@VisibleForTesting
internal companion object {
- val OPS_MIC_CAMERA = intArrayOf(AppOpsManager.OP_CAMERA,
- AppOpsManager.OP_PHONE_CALL_CAMERA, AppOpsManager.OP_RECORD_AUDIO,
- AppOpsManager.OP_PHONE_CALL_MICROPHONE,
- AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO)
- val OPS_LOCATION = intArrayOf(
- AppOpsManager.OP_COARSE_LOCATION,
- AppOpsManager.OP_FINE_LOCATION)
- val OPS = OPS_MIC_CAMERA + OPS_LOCATION
- val intentFilter = IntentFilter().apply {
- addAction(Intent.ACTION_USER_SWITCHED)
- addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
- addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)
- }
const val TAG = "PrivacyItemController"
- private const val MIC_CAMERA = SystemUiDeviceConfigFlags.PROPERTY_MIC_CAMERA_ENABLED
- private const val LOCATION = SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_ENABLED
- private const val DEFAULT_MIC_CAMERA = true
- private const val DEFAULT_LOCATION = false
@VisibleForTesting const val TIME_TO_HOLD_INDICATORS = 5000L
}
@@ -82,23 +55,18 @@ class PrivacyItemController @Inject constructor(
@Synchronized get() = field.toList() // Returns a shallow copy of the list
@Synchronized set
- private fun isMicCameraEnabled(): Boolean {
- return deviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- MIC_CAMERA, DEFAULT_MIC_CAMERA)
- }
-
- private fun isLocationEnabled(): Boolean {
- return deviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- LOCATION, DEFAULT_LOCATION)
- }
-
- private var currentUserIds = emptyList<Int>()
private var listening = false
private val callbacks = mutableListOf<WeakReference<Callback>>()
private val internalUiExecutor = MyExecutor(uiExecutor)
-
private var holdingRunnableCanceler: Runnable? = null
+ val micCameraAvailable
+ get() = privacyConfig.micCameraAvailable
+ val locationAvailable
+ get() = privacyConfig.locationAvailable
+ val allIndicatorsAvailable
+ get() = micCameraAvailable && locationAvailable && privacyConfig.mediaProjectionAvailable
+
private val notifyChanges = Runnable {
val list = privacyList
callbacks.forEach { it.get()?.onPrivacyItemsChanged(list) }
@@ -109,90 +77,33 @@ class PrivacyItemController @Inject constructor(
uiExecutor.execute(notifyChanges)
}
- var micCameraAvailable = isMicCameraEnabled()
- private set
- var locationAvailable = isLocationEnabled()
-
- var allIndicatorsAvailable = micCameraAvailable && locationAvailable
-
- private val devicePropertiesChangedListener =
- object : DeviceConfig.OnPropertiesChangedListener {
- override fun onPropertiesChanged(properties: DeviceConfig.Properties) {
- if (DeviceConfig.NAMESPACE_PRIVACY.equals(properties.getNamespace()) &&
- (properties.keyset.contains(MIC_CAMERA) ||
- properties.keyset.contains(LOCATION))) {
-
- // Running on the ui executor so can iterate on callbacks
- if (properties.keyset.contains(MIC_CAMERA)) {
- micCameraAvailable = properties.getBoolean(MIC_CAMERA, DEFAULT_MIC_CAMERA)
- allIndicatorsAvailable = micCameraAvailable && locationAvailable
- callbacks.forEach { it.get()?.onFlagMicCameraChanged(micCameraAvailable) }
- }
-
- if (properties.keyset.contains(LOCATION)) {
- locationAvailable = properties.getBoolean(LOCATION, DEFAULT_LOCATION)
- allIndicatorsAvailable = micCameraAvailable && locationAvailable
- callbacks.forEach { it.get()?.onFlagLocationChanged(locationAvailable) }
- }
- internalUiExecutor.updateListeningState()
- }
+ private val optionsCallback = object : PrivacyConfig.Callback {
+ override fun onFlagLocationChanged(flag: Boolean) {
+ callbacks.forEach { it.get()?.onFlagLocationChanged(flag) }
}
- }
- private val cb = object : AppOpsController.Callback {
- override fun onActiveStateChanged(
- code: Int,
- uid: Int,
- packageName: String,
- active: Boolean
- ) {
- // Check if we care about this code right now
- if (code in OPS_LOCATION && !locationAvailable) {
- return
- }
- val userId = UserHandle.getUserId(uid)
- if (userId in currentUserIds ||
- code == AppOpsManager.OP_PHONE_CALL_MICROPHONE ||
- code == AppOpsManager.OP_PHONE_CALL_CAMERA) {
- logger.logUpdatedItemFromAppOps(code, uid, packageName, active)
- update(false)
- }
+ override fun onFlagMicCameraChanged(flag: Boolean) {
+ callbacks.forEach { it.get()?.onFlagMicCameraChanged(flag) }
}
- }
- @VisibleForTesting
- internal var userTrackerCallback = object : UserTracker.Callback {
- override fun onUserChanged(newUser: Int, userContext: Context) {
- update(true)
+ override fun onFlagMediaProjectionChanged(flag: Boolean) {
+ callbacks.forEach { it.get()?.onFlagMediaProjectionChanged(flag) }
}
+ }
- override fun onProfilesChanged(profiles: List<UserInfo>) {
- update(true)
+ private val privacyItemMonitorCallback = object : PrivacyItemMonitor.Callback {
+ override fun onPrivacyItemsChanged() {
+ update()
}
}
init {
- deviceConfigProxy.addOnPropertiesChangedListener(
- DeviceConfig.NAMESPACE_PRIVACY,
- uiExecutor,
- devicePropertiesChangedListener)
dumpManager.registerDumpable(TAG, this)
+ privacyConfig.addCallback(optionsCallback)
}
- private fun unregisterListener() {
- userTracker.removeCallback(userTrackerCallback)
- }
-
- private fun registerReceiver() {
- userTracker.addCallback(userTrackerCallback, bgExecutor)
- }
-
- private fun update(updateUsers: Boolean) {
+ private fun update() {
bgExecutor.execute {
- if (updateUsers) {
- currentUserIds = userTracker.userProfiles.map { it.id }
- logger.logCurrentProfilesChanged(currentUserIds)
- }
updateListAndNotifyChanges.run()
}
}
@@ -207,20 +118,17 @@ class PrivacyItemController @Inject constructor(
* main thread.
*/
private fun setListeningState() {
- val listen = !callbacks.isEmpty() and
- (micCameraAvailable || locationAvailable)
+ val listen = callbacks.isNotEmpty()
if (listening == listen) return
listening = listen
if (listening) {
- appOpsController.addCallback(OPS, cb)
- registerReceiver()
- update(true)
+ privacyItemMonitors.forEach { it.startListening(privacyItemMonitorCallback) }
+ update()
} else {
- appOpsController.removeCallback(OPS, cb)
- unregisterListener()
+ privacyItemMonitors.forEach { it.stopListening() }
// Make sure that we remove all indicators and notify listeners if we are not
// listening anymore due to indicators being disabled
- update(false)
+ update()
}
}
@@ -259,11 +167,7 @@ class PrivacyItemController @Inject constructor(
privacyList = emptyList()
return
}
- val list = appOpsController.getActiveAppOps(true).filter {
- UserHandle.getUserId(it.uid) in currentUserIds ||
- it.code == AppOpsManager.OP_PHONE_CALL_MICROPHONE ||
- it.code == AppOpsManager.OP_PHONE_CALL_CAMERA
- }.mapNotNull { toPrivacyItem(it) }.distinct()
+ val list = privacyItemMonitors.flatMap { it.getActivePrivacyItems() }.distinct()
privacyList = processNewList(list)
}
@@ -309,35 +213,11 @@ class PrivacyItemController @Inject constructor(
}
}
- private fun toPrivacyItem(appOpItem: AppOpItem): PrivacyItem? {
- val type: PrivacyType = when (appOpItem.code) {
- AppOpsManager.OP_PHONE_CALL_CAMERA,
- AppOpsManager.OP_CAMERA -> PrivacyType.TYPE_CAMERA
- AppOpsManager.OP_COARSE_LOCATION,
- AppOpsManager.OP_FINE_LOCATION -> PrivacyType.TYPE_LOCATION
- AppOpsManager.OP_PHONE_CALL_MICROPHONE,
- AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO,
- AppOpsManager.OP_RECORD_AUDIO -> PrivacyType.TYPE_MICROPHONE
- else -> return null
- }
- if (type == PrivacyType.TYPE_LOCATION && !locationAvailable) {
- return null
- }
- val app = PrivacyApplication(appOpItem.packageName, appOpItem.uid)
- return PrivacyItem(type, app, appOpItem.timeStartedElapsed, appOpItem.isDisabled)
- }
-
- interface Callback {
+ interface Callback : PrivacyConfig.Callback {
fun onPrivacyItemsChanged(privacyItems: List<PrivacyItem>)
@JvmDefault
fun onFlagAllChanged(flag: Boolean) {}
-
- @JvmDefault
- fun onFlagMicCameraChanged(flag: Boolean) {}
-
- @JvmDefault
- fun onFlagLocationChanged(flag: Boolean) {}
}
private class NotifyChangesToCallback(
@@ -350,21 +230,34 @@ class PrivacyItemController @Inject constructor(
}
override fun dump(pw: PrintWriter, args: Array<out String>) {
- pw.println("PrivacyItemController state:")
- pw.println(" Listening: $listening")
- pw.println(" Current user ids: $currentUserIds")
- pw.println(" Privacy Items:")
- privacyList.forEach {
- pw.print(" ")
- pw.println(it.toString())
- }
- pw.println(" Callbacks:")
- callbacks.forEach {
- it.get()?.let {
- pw.print(" ")
- pw.println(it.toString())
+ val ipw = pw.asIndenting()
+ ipw.println("PrivacyItemController state:")
+ ipw.withIncreasedIndent {
+ ipw.println("Listening: $listening")
+ ipw.println("Privacy Items:")
+ ipw.withIncreasedIndent {
+ privacyList.forEach {
+ ipw.println(it.toString())
+ }
+ }
+
+ ipw.println("Callbacks:")
+ ipw.withIncreasedIndent {
+ callbacks.forEach {
+ it.get()?.let {
+ ipw.println(it.toString())
+ }
+ }
+ }
+
+ ipw.println("PrivacyItemMonitors:")
+ ipw.withIncreasedIndent {
+ privacyItemMonitors.forEach {
+ it.dump(ipw, args)
+ }
}
}
+ ipw.flush()
}
private inner class MyExecutor(
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemMonitor.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemMonitor.kt
new file mode 100644
index 000000000000..5bae31e1886e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemMonitor.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.privacy
+
+import com.android.systemui.Dumpable
+
+interface PrivacyItemMonitor : Dumpable {
+ fun startListening(callback: Callback)
+ fun stopListening()
+ fun getActivePrivacyItems(): List<PrivacyItem>
+
+ interface Callback {
+ fun onPrivacyItemsChanged()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyModule.java b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyModule.java
new file mode 100644
index 000000000000..732a3103d4aa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyModule.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.privacy;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.multibindings.IntoSet;
+
+/** Dagger module for privacy. */
+@Module
+public interface PrivacyModule {
+ /** Binds {@link AppOpsPrivacyItemMonitor} into the set of {@link PrivacyItemMonitor}. */
+ @Binds
+ @IntoSet
+ PrivacyItemMonitor bindAppOpsPrivacyItemMonitor(
+ AppOpsPrivacyItemMonitor appOpsPrivacyItemMonitor);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt b/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
index 1a268b5f94a9..1ea93474f954 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
@@ -44,6 +44,16 @@ class PrivacyLogger @Inject constructor(
})
}
+ fun logUpdatedItemFromMediaProjection(uid: Int, packageName: String, active: Boolean) {
+ log(LogLevel.INFO, {
+ int1 = uid
+ str1 = packageName
+ bool1 = active
+ }, {
+ "MediaProjection: $str1($int1), active=$bool1"
+ })
+ }
+
fun logRetrievedPrivacyItemsList(list: List<PrivacyItem>) {
log(LogLevel.INFO, {
str1 = listToString(list)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
index 8d2b14a60632..80eacd1f3e63 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
@@ -44,6 +44,7 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.TASK_MANAGER_SHOW_FOOTER_DOT
import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.animation.DialogLaunchAnimator
@@ -81,6 +82,8 @@ class FgsManagerController @Inject constructor(
companion object {
private val LOG_TAG = FgsManagerController::class.java.simpleName
+ private const val DEFAULT_TASK_MANAGER_ENABLED = true
+ private const val DEFAULT_TASK_MANAGER_SHOW_FOOTER_DOT = false
}
var changesSinceDialog = false
@@ -88,6 +91,8 @@ class FgsManagerController @Inject constructor(
var isAvailable = false
private set
+ var showFooterDot = false
+ private set
private val lock = Any()
@@ -151,10 +156,14 @@ class FgsManagerController @Inject constructor(
deviceConfigProxy.addOnPropertiesChangedListener(NAMESPACE_SYSTEMUI,
backgroundExecutor) {
isAvailable = it.getBoolean(TASK_MANAGER_ENABLED, isAvailable)
+ showFooterDot =
+ it.getBoolean(TASK_MANAGER_SHOW_FOOTER_DOT, showFooterDot)
}
- isAvailable = deviceConfigProxy
- .getBoolean(NAMESPACE_SYSTEMUI, TASK_MANAGER_ENABLED, true)
+ isAvailable = deviceConfigProxy.getBoolean(NAMESPACE_SYSTEMUI,
+ TASK_MANAGER_ENABLED, DEFAULT_TASK_MANAGER_ENABLED)
+ showFooterDot = deviceConfigProxy.getBoolean(NAMESPACE_SYSTEMUI,
+ TASK_MANAGER_SHOW_FOOTER_DOT, DEFAULT_TASK_MANAGER_SHOW_FOOTER_DOT)
dumpManager.registerDumpable(this)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
index abebf3e80b21..875493d73f9e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
@@ -17,6 +17,7 @@
package com.android.systemui.qs;
import static com.android.systemui.qs.dagger.QSFragmentModule.QS_FGS_MANAGER_FOOTER_VIEW;
+import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat;
import android.content.Context;
import android.view.View;
@@ -141,16 +142,16 @@ public class QSFgsManagerFooter implements View.OnClickListener,
public void handleRefreshState() {
mMainExecutor.execute(() -> {
- CharSequence text = mContext.getResources().getQuantityString(
- R.plurals.fgs_manager_footer_label, mNumPackages, mNumPackages);
+ CharSequence text = icuMessageFormat(mContext.getResources(),
+ R.string.fgs_manager_footer_label, mNumPackages);
mFooterText.setText(text);
mNumberView.setText(Integer.toString(mNumPackages));
mNumberView.setContentDescription(text);
if (mFgsManagerController.shouldUpdateFooterVisibility()) {
mRootView.setVisibility(mNumPackages > 0
&& mFgsManagerController.isAvailable() ? View.VISIBLE : View.GONE);
- int dotVis =
- mFgsManagerController.getChangesSinceDialog() ? View.VISIBLE : View.GONE;
+ int dotVis = mFgsManagerController.getShowFooterDot()
+ && mFgsManagerController.getChangesSinceDialog() ? View.VISIBLE : View.GONE;
mDotView.setVisibility(dotVis);
mCollapsedDotView.setVisibility(dotVis);
if (mVisibilityChangedListener != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index c3d78088e694..8c5e6cc63147 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -57,7 +57,6 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.util.LifecycleFragment;
-import com.android.systemui.util.Utils;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -624,7 +623,6 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
if (mQSAnimator != null) {
mQSAnimator.setPosition(expansion);
}
- updateMediaPositions();
}
private void setAlphaAnimationProgress(float progress) {
@@ -661,54 +659,6 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
- mQSPanelScrollView.getPaddingBottom());
}
- private void updateMediaPositions() {
- if (Utils.useQsMediaPlayer(getContext())) {
- mContainer.getLocationOnScreen(mTmpLocation);
- float absoluteBottomPosition = mTmpLocation[1] + mContainer.getHeight();
- // The Media can be scrolled off screen by default, let's offset it
- float expandedMediaPosition = absoluteBottomPosition - mQSPanelScrollView.getScrollY()
- + mQSPanelScrollView.getScrollRange();
- pinToBottom(expandedMediaPosition, mQsMediaHost, true /* expanded */);
- // The expanded media host should never move above the laid out position
- pinToBottom(absoluteBottomPosition, mQqsMediaHost, false /* expanded */);
- }
- }
-
- private void pinToBottom(float absoluteBottomPosition, MediaHost mediaHost, boolean expanded) {
- View hostView = mediaHost.getHostView();
- // On keyguard we cross-fade to expanded, so no need to pin it.
- // If the collapsed qs isn't visible, we also just keep it at the laid out position.
- if (mLastQSExpansion > 0 && !isKeyguardState() && mQqsMediaHost.getVisible()) {
- float targetPosition = absoluteBottomPosition - getTotalBottomMargin(hostView)
- - hostView.getHeight();
- float currentPosition = mediaHost.getCurrentBounds().top
- - hostView.getTranslationY();
- float translationY = targetPosition - currentPosition;
- if (expanded) {
- // Never go below the laid out position. This is necessary since the qs panel can
- // change in height and we don't want to ever go below it's position
- translationY = Math.min(translationY, 0);
- } else {
- translationY = Math.max(translationY, 0);
- }
- hostView.setTranslationY(translationY);
- } else {
- hostView.setTranslationY(0);
- }
- }
-
- private float getTotalBottomMargin(View startView) {
- int result = 0;
- View child = startView;
- View parent = (View) startView.getParent();
- while (!(parent instanceof QSContainerImpl) && parent != null) {
- result += parent.getHeight() - child.getBottom();
- child = parent;
- parent = (View) parent.getParent();
- }
- return result;
- }
-
private boolean headerWillBeAnimating() {
return mState == StatusBarState.KEYGUARD && mShowCollapsedOnKeyguard
&& !isKeyguardState();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index da5202bc3645..9a0d0d9656ca 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles;
+import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat;
+
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
@@ -182,10 +184,8 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
List<CachedBluetoothDevice> connectedDevices = mController.getConnectedDevices();
if (enabled && connected && !connectedDevices.isEmpty()) {
if (connectedDevices.size() > 1) {
- // TODO(b/76102598): add a new string for "X connected devices" after P
- return mContext.getResources().getQuantityString(
- R.plurals.quick_settings_hotspot_secondary_label_num_devices,
- connectedDevices.size(),
+ return icuMessageFormat(mContext.getResources(),
+ R.string.quick_settings_hotspot_secondary_label_num_devices,
connectedDevices.size());
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 7c8e77b5d993..b6f6e933bf84 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles;
+import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat;
+
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
@@ -186,9 +188,8 @@ public class HotspotTile extends QSTileImpl<BooleanState> {
return mContext.getString(
R.string.quick_settings_hotspot_secondary_label_data_saver_enabled);
} else if (numConnectedDevices > 0 && isActive) {
- return mContext.getResources().getQuantityString(
- R.plurals.quick_settings_hotspot_secondary_label_num_devices,
- numConnectedDevices,
+ return icuMessageFormat(mContext.getResources(),
+ R.string.quick_settings_hotspot_secondary_label_num_devices,
numConnectedDevices);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index aa80b730d24f..cc3121ddc0e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -398,11 +398,11 @@ public class CommandQueue extends IStatusBar.Stub implements
/**
* @see IStatusBar#showToast(int, String, IBinder, CharSequence, IBinder, int,
- * ITransientNotificationCallback)
+ * ITransientNotificationCallback, int)
*/
default void showToast(int uid, String packageName, IBinder token, CharSequence text,
IBinder windowToken, int duration,
- @Nullable ITransientNotificationCallback callback) { }
+ @Nullable ITransientNotificationCallback callback, int displayId) { }
/**
* @see IStatusBar#hideToast(String, IBinder) (String, IBinder)
@@ -944,7 +944,8 @@ public class CommandQueue extends IStatusBar.Stub implements
@Override
public void showToast(int uid, String packageName, IBinder token, CharSequence text,
- IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) {
+ IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback,
+ int displayId) {
synchronized (mLock) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = packageName;
@@ -954,6 +955,7 @@ public class CommandQueue extends IStatusBar.Stub implements
args.arg5 = callback;
args.argi1 = uid;
args.argi2 = duration;
+ args.argi3 = displayId;
mHandler.obtainMessage(MSG_SHOW_TOAST, args).sendToTarget();
}
}
@@ -1600,9 +1602,10 @@ public class CommandQueue extends IStatusBar.Stub implements
(ITransientNotificationCallback) args.arg5;
int uid = args.argi1;
int duration = args.argi2;
+ int displayId = args.argi3;
for (Callbacks callbacks : mCallbacks) {
callbacks.showToast(uid, packageName, token, text, windowToken, duration,
- callback);
+ callback, displayId);
}
break;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index d71dec8ff396..5cdd01f0ee0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -68,6 +68,7 @@ import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.statusbar.policy.RemoteInputView;
import com.android.systemui.util.DumpUtilsKt;
+import com.android.systemui.util.ListenerSet;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -75,6 +76,7 @@ import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import java.util.function.Consumer;
import dagger.Lazy;
@@ -118,6 +120,8 @@ public class NotificationRemoteInputManager implements Dumpable {
protected Callback mCallback;
private final List<RemoteInputController.Callback> mControllerCallbacks = new ArrayList<>();
+ private final ListenerSet<Consumer<NotificationEntry>> mActionPressListeners =
+ new ListenerSet<>();
private final InteractionHandler mInteractionHandler = new InteractionHandler() {
@@ -401,6 +405,14 @@ public class NotificationRemoteInputManager implements Dumpable {
}
}
+ public void addActionPressListener(Consumer<NotificationEntry> listener) {
+ mActionPressListeners.addIfAbsent(listener);
+ }
+
+ public void removeActionPressListener(Consumer<NotificationEntry> listener) {
+ mActionPressListeners.remove(listener);
+ }
+
/**
* Activates a given {@link RemoteInput}
*
@@ -634,6 +646,9 @@ public class NotificationRemoteInputManager implements Dumpable {
if (mRemoteInputListener != null) {
mRemoteInputListener.releaseNotificationIfKeptForRemoteInputHistory(entry);
}
+ for (Consumer<NotificationEntry> listener : mActionPressListeners) {
+ listener.accept(entry);
+ }
}
/** Returns whether the notification should be lifetime extended for smart reply history */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 333815f6b11a..0280e0b729a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -44,6 +44,7 @@ import android.view.animation.Interpolator;
import androidx.annotation.NonNull;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.jank.InteractionJankMonitor.Configuration;
import com.android.internal.logging.UiEventLogger;
@@ -335,10 +336,24 @@ public class StatusBarStateControllerImpl implements
? Interpolators.FAST_OUT_SLOW_IN
: Interpolators.TOUCH_RESPONSE_REVERSE;
}
- mDarkAnimator = ObjectAnimator.ofFloat(this, SET_DARK_AMOUNT_PROPERTY, mDozeAmountTarget);
- mDarkAnimator.setInterpolator(Interpolators.LINEAR);
- mDarkAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP);
- mDarkAnimator.addListener(new AnimatorListenerAdapter() {
+ if (mDozeAmount == 1f && !mIsDozing) {
+ // Workaround to force relayoutWindow to be called a frame earlier. Otherwise, if
+ // mDozeAmount = 1f, then neither start() nor the first frame of the animation will
+ // cause the scrim opacity to change, which ultimately results in an extra relayout and
+ // causes us to miss a frame. By settings the doze amount to be <1f a frame earlier,
+ // we can batch the relayout with the one in NotificationShadeWindowControllerImpl.
+ setDozeAmountInternal(0.99f);
+ }
+ mDarkAnimator = createDarkAnimator();
+ }
+
+ @VisibleForTesting
+ protected ObjectAnimator createDarkAnimator() {
+ ObjectAnimator darkAnimator = ObjectAnimator.ofFloat(
+ this, SET_DARK_AMOUNT_PROPERTY, mDozeAmountTarget);
+ darkAnimator.setInterpolator(Interpolators.LINEAR);
+ darkAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP);
+ darkAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
cancelInteractionJankMonitor();
@@ -354,7 +369,8 @@ public class StatusBarStateControllerImpl implements
beginInteractionJankMonitor();
}
});
- mDarkAnimator.start();
+ darkAnimator.start();
+ return darkAnimator;
}
private void setDozeAmountInternal(float dozeAmount) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index f84a6df05422..9f9fba437869 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.notification;
-import android.util.MathUtils;
import android.util.Pools;
import android.view.View;
import android.view.animation.Interpolator;
@@ -99,10 +98,7 @@ public class TransformState {
if (sameAs(otherState)) {
ensureVisible();
} else {
- CrossFadeHelper.fadeIn(
- mTransformedView,
- MathUtils.constrainedMap(0, 1, 0.45f, 1, transformationAmount),
- false /* remap */);
+ CrossFadeHelper.fadeIn(mTransformedView, transformationAmount, true /* remap */);
}
transformViewFullyFrom(otherState, transformationAmount);
}
@@ -298,10 +294,7 @@ public class TransformState {
}
return false;
} else {
- CrossFadeHelper.fadeOut(
- mTransformedView,
- MathUtils.constrainedMap(0, 1, 0, 0.55f, transformationAmount),
- false /* remap */);
+ CrossFadeHelper.fadeOut(mTransformedView, transformationAmount);
}
transformViewFullyTo(otherState, transformationAmount);
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
index da0169bd6dc4..a61db4107c94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
@@ -18,7 +18,6 @@ package com.android.systemui.statusbar.notification.collection.coordinator
import android.app.Notification
import android.app.Notification.GROUP_ALERT_SUMMARY
import android.util.ArrayMap
-import android.util.ArraySet
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.statusbar.NotificationRemoteInputManager
import com.android.systemui.statusbar.notification.collection.GroupEntry
@@ -41,6 +40,7 @@ import com.android.systemui.statusbar.policy.HeadsUpManager
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.time.SystemClock
+import java.util.function.Consumer
import javax.inject.Inject
/**
@@ -85,6 +85,7 @@ class HeadsUpCoordinator @Inject constructor(
pipeline.addOnBeforeFinalizeFilterListener(::onBeforeFinalizeFilter)
pipeline.addPromoter(mNotifPromoter)
pipeline.addNotificationLifetimeExtender(mLifetimeExtender)
+ mRemoteInputManager.addActionPressListener(mActionPressListener)
}
private fun onHeadsUpViewBound(entry: NotificationEntry) {
@@ -448,6 +449,14 @@ class HeadsUpCoordinator @Inject constructor(
(entry.sbn.notification.flags and Notification.FLAG_ONLY_ALERT_ONCE) == 0)
}
+ /** When an action is pressed on a notification, end HeadsUp lifetime extension. */
+ private val mActionPressListener = Consumer<NotificationEntry> { entry ->
+ if (mNotifsExtendingLifetime.contains(entry)) {
+ val removeInMillis = mHeadsUpManager.getEarliestRemovalTime(entry.key)
+ mExecutor.executeDelayed({ endNotifLifetimeExtensionIfExtended(entry) }, removeInMillis)
+ }
+ }
+
private val mLifetimeExtender = object : NotifLifetimeExtender {
override fun getName() = TAG
@@ -503,6 +512,7 @@ class HeadsUpCoordinator @Inject constructor(
private val mOnHeadsUpChangedListener = object : OnHeadsUpChangedListener {
override fun onHeadsUpStateChanged(entry: NotificationEntry, isHeadsUp: Boolean) {
if (!isHeadsUp) {
+ mNotifPromoter.invalidateList()
mHeadsUpViewBinder.unbindHeadsUpView(entry)
endNotifLifetimeExtensionIfExtended(entry)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 4c7b2bbfb6d9..b84a797bbb6f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.collection.inflation;
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC;
+
import static java.util.Objects.requireNonNull;
import android.annotation.Nullable;
@@ -250,9 +252,11 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
params.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
params.setUseLowPriority(isLowPriority);
- // TODO: Replace this API with RowContentBindParams directly. Also move to a separate
- // redaction controller.
- row.setNeedsRedaction(mNotificationLockscreenUserManager.needsRedaction(entry));
+ if (mNotificationLockscreenUserManager.needsRedaction(entry)) {
+ params.requireContentViews(FLAG_CONTENT_VIEW_PUBLIC);
+ } else {
+ params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC);
+ }
params.rebindAllContentViews();
mRowContentBindStage.requestRebind(entry, en -> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index e210f193b0a1..a063dbd99626 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -194,6 +194,10 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
return false;
}
+ if (!canAlertHeadsUpCommon(entry)) {
+ return false;
+ }
+
if (!canAlertAwakeCommon(entry)) {
return false;
}
@@ -267,6 +271,11 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
return false;
}
+ if (!canAlertHeadsUpCommon(entry)) {
+ mLogger.logNoPulsingNoAlert(sbn);
+ return false;
+ }
+
if (entry.shouldSuppressAmbient()) {
mLogger.logNoPulsingNoAmbientEffect(sbn);
return false;
@@ -294,12 +303,6 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
return false;
}
- // Don't alert notifications that are suppressed due to group alert behavior
- if (sbn.isGroup() && sbn.getNotification().suppressAlertingDueToGrouping()) {
- mLogger.logNoAlertingGroupAlertBehavior(sbn);
- return false;
- }
-
for (int i = 0; i < mSuppressors.size(); i++) {
if (mSuppressors.get(i).suppressInterruptions(entry)) {
mLogger.logNoAlertingSuppressedBy(sbn, mSuppressors.get(i), /* awake */ false);
@@ -307,13 +310,31 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
}
}
- if (entry.hasJustLaunchedFullScreenIntent()) {
- mLogger.logNoAlertingRecentFullscreen(sbn);
+ if (mKeyguardNotificationVisibilityProvider.shouldHideNotification(entry)) {
+ mLogger.keyguardHideNotification(entry.getKey());
return false;
}
- if (mKeyguardNotificationVisibilityProvider.shouldHideNotification(entry)) {
- mLogger.keyguardHideNotification(entry.getKey());
+ return true;
+ }
+
+ /**
+ * Common checks for heads up notifications on regular and AOD displays.
+ *
+ * @param entry the entry to check
+ * @return true if these checks pass, false if the notification should not alert
+ */
+ private boolean canAlertHeadsUpCommon(NotificationEntry entry) {
+ StatusBarNotification sbn = entry.getSbn();
+
+ // Don't alert notifications that are suppressed due to group alert behavior
+ if (sbn.isGroup() && sbn.getNotification().suppressAlertingDueToGrouping()) {
+ mLogger.logNoAlertingGroupAlertBehavior(sbn);
+ return false;
+ }
+
+ if (entry.hasJustLaunchedFullScreenIntent()) {
+ mLogger.logNoAlertingRecentFullscreen(sbn);
return false;
}
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 2bef4de295b3..e733970ab65f 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
@@ -42,7 +42,6 @@ import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
@@ -56,7 +55,6 @@ import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.MathUtils;
import android.util.Property;
-import android.util.Slog;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -90,8 +88,8 @@ import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
-import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
import com.android.systemui.statusbar.notification.FeedbackIcon;
+import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
import com.android.systemui.statusbar.notification.NotificationFadeAware;
import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController;
import com.android.systemui.statusbar.notification.NotificationUtils;
@@ -1505,8 +1503,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mUseIncreasedHeadsUpHeight = use;
}
+ /** @deprecated TODO: Remove this when the old pipeline code is removed. */
+ @Deprecated
public void setNeedsRedaction(boolean needsRedaction) {
- // TODO: Move inflation logic out of this call and remove this method
if (mNeedsRedaction != needsRedaction) {
mNeedsRedaction = needsRedaction;
if (!isRemoved()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
index 56f8e087d64d..40a44ffd7fe3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.row;
+import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat;
+
import android.annotation.Nullable;
import android.app.Notification;
import android.content.Context;
@@ -136,8 +138,8 @@ public class HybridGroupManager {
if (!text.equals(reusableView.getText())) {
reusableView.setText(text);
}
- String contentDescription = String.format(mContext.getResources().getQuantityString(
- R.plurals.notification_group_overflow_description, number), number);
+ String contentDescription = icuMessageFormat(mContext.getResources(),
+ R.string.notification_group_overflow_description, number);
reusableView.setContentDescription(contentDescription);
reusableView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mOverflowNumberSize);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
index 7269f5545163..512b04968166 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.row;
+import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -243,11 +245,11 @@ public class NotificationSnooze extends LinearLayout
private SnoozeOption createOption(int minutes, int accessibilityActionId) {
Resources res = getResources();
boolean showInHours = minutes >= 60;
- int pluralResId = showInHours
- ? R.plurals.snoozeHourOptions
- : R.plurals.snoozeMinuteOptions;
+ int stringResId = showInHours
+ ? R.string.snoozeHourOptions
+ : R.string.snoozeMinuteOptions;
int count = showInHours ? (minutes / 60) : minutes;
- String description = res.getQuantityString(pluralResId, count, count);
+ String description = icuMessageFormat(res, stringResId, count);
String resultText = String.format(res.getString(R.string.snoozed_for_time), description);
AccessibilityAction action = new AccessibilityAction(accessibilityActionId, description);
final int index = resultText.indexOf(description);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
index f26ecc32821d..a52f638e7c26 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
@@ -102,8 +102,9 @@ public final class RowContentBindParams {
* @see InflationFlag
*/
public void markContentViewsFreeable(@InflationFlag int contentViews) {
+ @InflationFlag int existingContentViews = contentViews &= mContentViews;
mContentViews &= ~contentViews;
- mDirtyContentViews &= ~contentViews;
+ mDirtyContentViews |= existingContentViews;
}
public @InflationFlag int getContentViews() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index a552f999aeb4..a76f0827fc18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -1312,6 +1312,7 @@ public class NotificationChildrenContainer extends ViewGroup
}
float bottomRoundness = last ? currentBottomRoundness : 0.0f;
child.setBottomRoundness(bottomRoundness, isShown() /* animate */);
+ child.setTopRoundness(0.0f, false /* animate */);
last = false;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
index 6287857e7be9..22234b1ef17d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
@@ -58,7 +58,7 @@ constructor(
private var maxKeyguardNotifications by notNull<Int>()
/** Minimum space between two notifications, see [calculateGapAndDividerHeight]. */
- private var dividerHeight by notNull<Int>()
+ private var dividerHeight by notNull<Float>()
init {
updateResources()
@@ -142,9 +142,13 @@ constructor(
if (i == children.lastIndex) {
0f // No shelf needed.
} else {
+ val firstViewInShelfIndex = i + 1
val spaceBeforeShelf =
calculateGapAndDividerHeight(
- stack, previous = currentNotification, current = children[i + 1], i)
+ stack,
+ previous = currentNotification,
+ current = children[firstViewInShelfIndex],
+ currentIndex = firstViewInShelfIndex)
spaceBeforeShelf + shelfIntrinsicHeight
}
@@ -156,16 +160,17 @@ constructor(
maxKeyguardNotifications =
infiniteIfNegative(resources.getInteger(R.integer.keyguard_max_notification_count))
- dividerHeight = max(1, resources.getDimensionPixelSize(R.dimen.notification_divider_height))
+ dividerHeight =
+ max(1f, resources.getDimensionPixelSize(R.dimen.notification_divider_height).toFloat())
}
private val NotificationStackScrollLayout.childrenSequence: Sequence<ExpandableView>
get() = children.map { it as ExpandableView }
@VisibleForTesting
- fun onLockscreen() : Boolean {
- return statusBarStateController.state == KEYGUARD
- && lockscreenShadeTransitionController.fractionToShade == 0f
+ fun onLockscreen(): Boolean {
+ return statusBarStateController.state == KEYGUARD &&
+ lockscreenShadeTransitionController.fractionToShade == 0f
}
@VisibleForTesting
@@ -207,11 +212,12 @@ constructor(
stack: NotificationStackScrollLayout,
previous: ExpandableView?,
current: ExpandableView?,
- visibleIndex: Int
+ currentIndex: Int
): Float {
- var height = stack.calculateGapHeight(previous, current, visibleIndex)
- height += dividerHeight
- return height
+ if (currentIndex == 0) {
+ return 0f
+ }
+ return stack.calculateGapHeight(previous, current, currentIndex) + dividerHeight
}
private fun NotificationStackScrollLayout.showableChildren() =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 9eb5f792011f..d5023ffd8b37 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -550,6 +550,9 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
if (!mUpdateMonitor.isDeviceInteractive()) {
if (!mKeyguardViewController.isShowing()
&& !mScreenOffAnimationController.isKeyguardShowDelayed()) {
+ if (mKeyguardStateController.isUnlocked()) {
+ return MODE_WAKE_AND_UNLOCK;
+ }
return MODE_ONLY_WAKE;
} else if (mDozeScrimController.isPulsing() && unlockingAllowed) {
return MODE_WAKE_AND_UNLOCK_PULSING;
@@ -579,7 +582,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
mUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric);
boolean deviceDreaming = mUpdateMonitor.isDreaming();
boolean bypass = mKeyguardBypassController.getBypassEnabled()
- || mKeyguardBypassController.getUserHasDeviceEntryIntent();
+ || mAuthController.isUdfpsFingerDown();
if (!mUpdateMonitor.isDeviceInteractive()) {
if (!mKeyguardViewController.isShowing()) {
return bypass ? MODE_WAKE_AND_UNLOCK : MODE_ONLY_WAKE;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index a9692a306c21..b3e0073de7a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -83,7 +83,6 @@ import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
-import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
@@ -781,7 +780,8 @@ public class CentralSurfacesImpl extends CoreStartable implements
InteractionJankMonitor jankMonitor,
DeviceStateManager deviceStateManager,
DreamOverlayStateController dreamOverlayStateController,
- WiredChargingRippleController wiredChargingRippleController) {
+ WiredChargingRippleController wiredChargingRippleController,
+ IDreamManager dreamManager) {
super(context);
mNotificationsController = notificationsController;
mFragmentService = fragmentService;
@@ -872,6 +872,7 @@ public class CentralSurfacesImpl extends CoreStartable implements
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
mStartingSurfaceOptional = startingSurfaceOptional;
mNotifPipelineFlags = notifPipelineFlags;
+ mDreamManager = dreamManager;
lockscreenShadeTransitionController.setCentralSurfaces(this);
statusBarWindowStateController.addListener(this::onStatusBarWindowStateChanged);
@@ -925,8 +926,6 @@ public class CentralSurfacesImpl extends CoreStartable implements
SysuiStatusBarStateController.RANK_STATUS_BAR);
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
- mDreamManager = IDreamManager.Stub.asInterface(
- ServiceManager.checkService(DreamService.DREAM_SERVICE));
mDisplay = mContext.getDisplay();
mDisplayId = mDisplay.getDisplayId();
@@ -1793,6 +1792,12 @@ public class CentralSurfacesImpl extends CoreStartable implements
collapseShade();
}
+ // We should exit the dream to prevent the activity from starting below the
+ // dream.
+ if (mKeyguardUpdateMonitor.isDreaming()) {
+ awakenDreams();
+ }
+
mActivityLaunchAnimator.startIntentWithAnimation(controller, animate,
intent.getPackage(), showOverLockscreenWhenLocked, (adapter) -> TaskStackBuilder
.create(mContext)
@@ -2738,6 +2743,10 @@ public class CentralSurfacesImpl extends CoreStartable implements
mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction,
afterKeyguardGone);
} else {
+ // If the keyguard isn't showing but the device is dreaming, we should exit the dream.
+ if (mKeyguardUpdateMonitor.isDreaming()) {
+ awakenDreams();
+ }
action.onDismiss();
}
}
@@ -3986,7 +3995,7 @@ public class CentralSurfacesImpl extends CoreStartable implements
protected WindowManager mWindowManager;
protected IWindowManager mWindowManagerService;
- private IDreamManager mDreamManager;
+ private final IDreamManager mDreamManager;
protected Display mDisplay;
private int mDisplayId;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index d179f7752fb6..b987f6815000 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -43,7 +43,6 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr
private var hasFaceFeature: Boolean
private var pendingUnlock: PendingUnlock? = null
private val listeners = mutableListOf<OnBypassStateChangedListener>()
- var userHasDeviceEntryIntent: Boolean = false // ie: attempted udfps auth
private val faceAuthEnabledChangedCallback = object : KeyguardStateController.Callback {
override fun onFaceAuthEnabledChanged() = notifyListeners()
@@ -217,7 +216,6 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr
pw.println(" launchingAffordance: $launchingAffordance")
pw.println(" qSExpanded: $qSExpanded")
pw.println(" hasFaceFeature: $hasFaceFeature")
- pw.println(" userHasDeviceEntryIntent: $userHasDeviceEntryIntent")
}
/** Registers a listener for bypass state changes. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 9afdfd651130..b66d21edb888 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -646,6 +646,7 @@ public class NotificationPanelViewController extends PanelViewController {
private int mScrimCornerRadius;
private int mScreenCornerRadius;
private boolean mQSAnimatingHiddenFromCollapsed;
+ private boolean mUseLargeScreenShadeHeader;
private int mQsClipTop;
private int mQsClipBottom;
@@ -1137,18 +1138,20 @@ public class NotificationPanelViewController extends PanelViewController {
final boolean splitShadeChanged = mSplitShadeEnabled != newSplitShadeEnabled;
mSplitShadeEnabled = newSplitShadeEnabled;
- boolean useLargeScreenShadeHeader =
- LargeScreenUtils.shouldUseLargeScreenShadeHeader(mView.getResources());
if (mQs != null) {
mQs.setInSplitShade(mSplitShadeEnabled);
}
+
+ mUseLargeScreenShadeHeader =
+ LargeScreenUtils.shouldUseLargeScreenShadeHeader(mView.getResources());
+
mLargeScreenShadeHeaderHeight =
mResources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height);
- mQuickQsHeaderHeight = useLargeScreenShadeHeader ? mLargeScreenShadeHeaderHeight :
+ mQuickQsHeaderHeight = mUseLargeScreenShadeHeader ? mLargeScreenShadeHeaderHeight :
SystemBarUtils.getQuickQsOffsetHeight(mView.getContext());
- int topMargin = useLargeScreenShadeHeader ? mLargeScreenShadeHeaderHeight :
+ int topMargin = mUseLargeScreenShadeHeader ? mLargeScreenShadeHeaderHeight :
mResources.getDimensionPixelSize(R.dimen.notification_panel_margin_top);
- mLargeScreenShadeHeaderController.setActive(useLargeScreenShadeHeader);
+ mLargeScreenShadeHeaderController.setActive(mUseLargeScreenShadeHeader);
mAmbientState.setStackTopMargin(topMargin);
mNotificationsQSContainerController.updateResources();
@@ -2436,8 +2439,8 @@ public class NotificationPanelViewController extends PanelViewController {
}
/**
- * Updates scrim bounds, QS clipping, and KSV clipping as well based on the bounds of the shade
- * and QS state.
+ * Updates scrim bounds, QS clipping, notifications clipping and keyguard status view clipping
+ * as well based on the bounds of the shade and QS state.
*/
private void setQSClippingBounds() {
final int qsPanelBottomY = calculateQsBottomPosition(computeQsExpansionFraction());
@@ -2513,6 +2516,13 @@ public class NotificationPanelViewController extends PanelViewController {
}
}
+ /**
+ * Applies clipping to quick settings, notifications layout and
+ * updates bounds of the notifications background (notifications scrim).
+ *
+ * The parameters are bounds of the notifications area rectangle, this function
+ * calculates bounds for the QS clipping based on the notifications bounds.
+ */
private void applyQSClippingBounds(int left, int top, int right, int bottom,
boolean qsVisible) {
if (!mAnimateNextNotificationBounds || mKeyguardStatusAreaClipBounds.isEmpty()) {
@@ -2648,12 +2658,10 @@ public class NotificationPanelViewController extends PanelViewController {
if (mTransitioningToFullShadeProgress > 0.0f) {
return mTransitionToFullShadeQSPosition;
} else {
- int qsBottomY = (int) getHeaderTranslation() + mQs.getQsMinExpansionHeight();
- if (qsExpansionFraction != 0.0) {
- qsBottomY = (int) MathUtils.lerp(
- qsBottomY, mQs.getDesiredHeight(), qsExpansionFraction);
- }
- return qsBottomY;
+ int qsBottomYFrom = (int) getHeaderTranslation() + mQs.getQsMinExpansionHeight();
+ int expandedTopMargin = mUseLargeScreenShadeHeader ? mLargeScreenShadeHeaderHeight : 0;
+ int qsBottomYTo = mQs.getDesiredHeight() + expandedTopMargin;
+ return (int) MathUtils.lerp(qsBottomYFrom, qsBottomYTo, qsExpansionFraction);
}
}
@@ -5012,7 +5020,8 @@ public class NotificationPanelViewController extends PanelViewController {
mDebugPaint.setColor(color);
canvas.drawLine(/* startX= */ 0, /* startY= */ y, /* stopX= */ mView.getWidth(),
/* stopY= */ y, mDebugPaint);
- canvas.drawText(label, /* x= */ 0, /* y= */ computeDebugYTextPosition(y), mDebugPaint);
+ canvas.drawText(label + " = " + y + "px", /* x= */ 0,
+ /* y= */ computeDebugYTextPosition(y), mDebugPaint);
}
private int computeDebugYTextPosition(int lineY) {
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
index 0758f8fc4fab..9eb34a42a0a9 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
@@ -27,6 +27,7 @@ import android.app.INotificationManager;
import android.app.ITransientNotificationCallback;
import android.content.Context;
import android.content.res.Configuration;
+import android.hardware.display.DisplayManager;
import android.os.IBinder;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -106,10 +107,15 @@ public class ToastUI extends CoreStartable implements CommandQueue.Callbacks {
@Override
@MainThread
public void showToast(int uid, String packageName, IBinder token, CharSequence text,
- IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) {
+ IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback,
+ int displayId) {
Runnable showToastRunnable = () -> {
UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
Context context = mContext.createContextAsUser(userHandle, 0);
+
+ DisplayManager mDisplayManager = mContext.getSystemService(DisplayManager.class);
+ Context displayContext = context.createDisplayContext(
+ mDisplayManager.getDisplay(displayId));
mToast = mToastFactory.createToast(mContext /* sysuiContext */, text, packageName,
userHandle.getIdentifier(), mOrientation);
@@ -118,7 +124,7 @@ public class ToastUI extends CoreStartable implements CommandQueue.Callbacks {
}
mCallback = callback;
- mPresenter = new ToastPresenter(context, mIAccessibilityManager,
+ mPresenter = new ToastPresenter(displayContext, mIAccessibilityManager,
mNotificationManager, packageName);
// Set as trusted overlay so touches can pass through toasts
mPresenter.getLayoutParams().setTrustedOverlay();
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index 4685c148e7e5..9a19d8d11190 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -39,6 +39,8 @@ import com.android.systemui.plugins.qs.QSFactory;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.EnhancedEstimates;
import com.android.systemui.power.dagger.PowerModule;
+import com.android.systemui.privacy.MediaProjectionPrivacyItemMonitor;
+import com.android.systemui.privacy.PrivacyItemMonitor;
import com.android.systemui.qs.dagger.QSModule;
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
import com.android.systemui.recents.Recents;
@@ -78,6 +80,7 @@ import javax.inject.Named;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
+import dagger.multibindings.IntoSet;
/**
* A dagger module for injecting default implementations of components of System UI that may be
@@ -212,4 +215,12 @@ public abstract class TvSystemUIModule {
NotificationListener notificationListener) {
return new TvNotificationHandler(context, notificationListener);
}
+
+ /**
+ * Binds {@link MediaProjectionPrivacyItemMonitor} into the set of {@link PrivacyItemMonitor}.
+ */
+ @Binds
+ @IntoSet
+ abstract PrivacyItemMonitor bindMediaProjectionPrivacyItemMonitor(
+ MediaProjectionPrivacyItemMonitor mediaProjectionPrivacyItemMonitor);
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/PluralMessageFormater.kt b/packages/SystemUI/src/com/android/systemui/util/PluralMessageFormater.kt
new file mode 100644
index 000000000000..83b471dff4b1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/PluralMessageFormater.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util
+
+import android.annotation.StringRes
+import android.content.res.Resources
+import android.util.PluralsMessageFormatter
+
+/**
+ * Utility method that provides the localized plural string for the given [messageId]
+ * using the [count] parameter.
+ */
+fun icuMessageFormat(res: Resources, @StringRes messageId: Int, count: Int): String {
+ return PluralsMessageFormatter.format(res, mapOf<String, Any>("count" to count), messageId)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
index 8c842f162e24..4cbc709aadc4 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
@@ -208,7 +208,7 @@ public class QuickAccessWalletController {
public void startQuickAccessUiIntent(ActivityStarter activityStarter,
ActivityLaunchAnimator.Controller animationController,
boolean hasCard) {
- mQuickAccessWalletClient.getWalletPendingIntent(mBgExecutor,
+ mQuickAccessWalletClient.getWalletPendingIntent(mExecutor,
walletPendingIntent -> {
if (walletPendingIntent != null) {
startQuickAccessViaPendingIntent(walletPendingIntent, activityStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index 3340f2fd5749..abe7ae1a0b1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -21,7 +21,9 @@ import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_DOCKED;
import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE;
import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSING;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSING_BRIGHT;
import static com.android.systemui.doze.DozeMachine.State.DOZE_REQUEST_PULSE;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_SUSPEND_TRIGGERS;
import static com.android.systemui.doze.DozeMachine.State.FINISH;
import static com.android.systemui.doze.DozeMachine.State.INITIALIZED;
import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
@@ -39,6 +41,8 @@ import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.UiModeManager;
+import android.content.res.Configuration;
import android.hardware.display.AmbientDisplayConfiguration;
import android.testing.AndroidTestingRunner;
import android.testing.UiThreadTest;
@@ -50,7 +54,6 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.wakelock.WakeLockFake;
import org.junit.Before;
@@ -70,9 +73,12 @@ public class DozeMachineTest extends SysuiTestCase {
private WakefulnessLifecycle mWakefulnessLifecycle;
@Mock
private DozeLog mDozeLog;
- @Mock private DockManager mDockManager;
+ @Mock
+ private DockManager mDockManager;
@Mock
private DozeHost mHost;
+ @Mock
+ private UiModeManager mUiModeManager;
private DozeServiceFake mServiceFake;
private WakeLockFake mWakeLockFake;
private AmbientDisplayConfiguration mConfigMock;
@@ -89,7 +95,7 @@ public class DozeMachineTest extends SysuiTestCase {
when(mDockManager.isHidden()).thenReturn(false);
mMachine = new DozeMachine(mServiceFake, mConfigMock, mWakeLockFake,
- mWakefulnessLifecycle, mock(BatteryController.class), mDozeLog, mDockManager,
+ mWakefulnessLifecycle, mUiModeManager, mDozeLog, mDockManager,
mHost, new DozeMachine.Part[]{mPartMock});
}
@@ -462,4 +468,64 @@ public class DozeMachineTest extends SysuiTestCase {
assertEquals(Display.STATE_ON, DOZE_REQUEST_PULSE.screenState(dozeParameters));
}
+
+ @Test
+ public void testTransitionToInitialized_carModeIsEnabled() {
+ when(mUiModeManager.getCurrentModeType()).thenReturn(Configuration.UI_MODE_TYPE_CAR);
+ mMachine.requestState(INITIALIZED);
+
+ verify(mPartMock).transitionTo(UNINITIALIZED, INITIALIZED);
+ verify(mPartMock).transitionTo(INITIALIZED, DOZE_SUSPEND_TRIGGERS);
+ assertEquals(DOZE_SUSPEND_TRIGGERS, mMachine.getState());
+ }
+
+ @Test
+ public void testTransitionToFinish_carModeIsEnabled() {
+ when(mUiModeManager.getCurrentModeType()).thenReturn(Configuration.UI_MODE_TYPE_CAR);
+ mMachine.requestState(INITIALIZED);
+ mMachine.requestState(FINISH);
+
+ assertEquals(FINISH, mMachine.getState());
+ }
+
+ @Test
+ public void testDozeToDozeSuspendTriggers_carModeIsEnabled() {
+ when(mUiModeManager.getCurrentModeType()).thenReturn(Configuration.UI_MODE_TYPE_CAR);
+ mMachine.requestState(INITIALIZED);
+ mMachine.requestState(DOZE);
+
+ assertEquals(DOZE_SUSPEND_TRIGGERS, mMachine.getState());
+ }
+
+ @Test
+ public void testDozeAoDToDozeSuspendTriggers_carModeIsEnabled() {
+ when(mUiModeManager.getCurrentModeType()).thenReturn(Configuration.UI_MODE_TYPE_CAR);
+ mMachine.requestState(INITIALIZED);
+ mMachine.requestState(DOZE_AOD);
+
+ assertEquals(DOZE_SUSPEND_TRIGGERS, mMachine.getState());
+ }
+
+ @Test
+ public void testDozePulsingBrightDozeSuspendTriggers_carModeIsEnabled() {
+ when(mUiModeManager.getCurrentModeType()).thenReturn(Configuration.UI_MODE_TYPE_CAR);
+ mMachine.requestState(INITIALIZED);
+ mMachine.requestState(DOZE_PULSING_BRIGHT);
+
+ assertEquals(DOZE_SUSPEND_TRIGGERS, mMachine.getState());
+ }
+
+ @Test
+ public void testDozeAodDockedDozeSuspendTriggers_carModeIsEnabled() {
+ when(mUiModeManager.getCurrentModeType()).thenReturn(Configuration.UI_MODE_TYPE_CAR);
+ mMachine.requestState(INITIALIZED);
+ mMachine.requestState(DOZE_AOD_DOCKED);
+
+ assertEquals(DOZE_SUSPEND_TRIGGERS, mMachine.getState());
+ }
+
+ @Test
+ public void testDozeSuppressTriggers_screenState() {
+ assertEquals(Display.STATE_OFF, DOZE_SUSPEND_TRIGGERS.screenState(null));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index 2e7b88d5fd38..03827dab0c96 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -24,6 +24,7 @@ import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSING;
import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE;
import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSING;
import static com.android.systemui.doze.DozeMachine.State.DOZE_REQUEST_PULSE;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_SUSPEND_TRIGGERS;
import static com.android.systemui.doze.DozeMachine.State.FINISH;
import static com.android.systemui.doze.DozeMachine.State.INITIALIZED;
import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
@@ -182,6 +183,21 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
}
@Test
+ public void dozeSuspendTriggers_doesNotUseLightSensor() {
+ // GIVEN the device is DOZE and the display state changes to ON
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE_SUSPEND_TRIGGERS);
+ waitForSensorManager();
+
+ // WHEN new sensor event sent
+ mSensor.sendSensorEvent(3);
+
+ // THEN brightness is NOT changed, it's set to the default brightness
+ assertNotSame(3, mServiceFake.screenBrightness);
+ assertEquals(DEFAULT_BRIGHTNESS, mServiceFake.screenBrightness);
+ }
+
+ @Test
public void aod_usesLightSensor() {
// GIVEN the device is DOZE_AOD and the display state changes to ON
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java
index aa0a909622bb..0f29dcd5a939 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java
@@ -16,19 +16,26 @@
package com.android.systemui.doze;
+import static android.app.UiModeManager.ACTION_ENTER_CAR_MODE;
+import static android.app.UiModeManager.ACTION_EXIT_CAR_MODE;
+
import static com.android.systemui.doze.DozeMachine.State.DOZE;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_SUSPEND_TRIGGERS;
import static com.android.systemui.doze.DozeMachine.State.FINISH;
import static com.android.systemui.doze.DozeMachine.State.INITIALIZED;
import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
-import static org.mockito.Matchers.anyObject;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.UiModeManager;
import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.Configuration;
import android.hardware.display.AmbientDisplayConfiguration;
import android.testing.AndroidTestingRunner;
@@ -77,7 +84,10 @@ public class DozeSuppressorTest extends SysuiTestCase {
@Captor
private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
+ @Captor
+ private ArgumentCaptor<IntentFilter> mIntentFilterCaptor;
private BroadcastReceiver mBroadcastReceiver;
+ private IntentFilter mIntentFilter;
@Captor
private ArgumentCaptor<DozeHost.Callback> mDozeHostCaptor;
@@ -122,15 +132,59 @@ public class DozeSuppressorTest extends SysuiTestCase {
}
@Test
- public void testEndDoze_carMode() {
+ public void testSuspendTriggersDoze_carMode() {
// GIVEN car mode
when(mUiModeManager.getCurrentModeType()).thenReturn(Configuration.UI_MODE_TYPE_CAR);
// WHEN dozing begins
mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED);
- // THEN doze immediately ends
- verify(mDozeMachine).requestState(FINISH);
+ // THEN doze continues with all doze triggers disabled.
+ verify(mDozeMachine).requestState(DOZE_SUSPEND_TRIGGERS);
+ }
+
+ @Test
+ public void testSuspendTriggersDoze_enterCarMode() {
+ // GIVEN currently dozing
+ mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED);
+ captureBroadcastReceiver();
+ mDozeSuppressor.transitionTo(INITIALIZED, DOZE);
+
+ // WHEN car mode entered
+ mBroadcastReceiver.onReceive(null, new Intent(ACTION_ENTER_CAR_MODE));
+
+ // THEN doze continues with all doze triggers disabled.
+ verify(mDozeMachine).requestState(DOZE_SUSPEND_TRIGGERS);
+ }
+
+ @Test
+ public void testDozeResume_exitCarMode() {
+ // GIVEN currently suspended, with AOD not enabled
+ when(mConfig.alwaysOnEnabled(anyInt())).thenReturn(false);
+ mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED);
+ captureBroadcastReceiver();
+ mDozeSuppressor.transitionTo(INITIALIZED, DOZE_SUSPEND_TRIGGERS);
+
+ // WHEN exiting car mode
+ mBroadcastReceiver.onReceive(null, new Intent(ACTION_EXIT_CAR_MODE));
+
+ // THEN doze is resumed
+ verify(mDozeMachine).requestState(DOZE);
+ }
+
+ @Test
+ public void testDozeAoDResume_exitCarMode() {
+ // GIVEN currently suspended, with AOD not enabled
+ when(mConfig.alwaysOnEnabled(anyInt())).thenReturn(true);
+ mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED);
+ captureBroadcastReceiver();
+ mDozeSuppressor.transitionTo(INITIALIZED, DOZE_SUSPEND_TRIGGERS);
+
+ // WHEN exiting car mode
+ mBroadcastReceiver.onReceive(null, new Intent(ACTION_EXIT_CAR_MODE));
+
+ // THEN doze AOD is resumed
+ verify(mDozeMachine).requestState(DOZE_AOD);
}
@Test
@@ -225,7 +279,11 @@ public class DozeSuppressorTest extends SysuiTestCase {
private void captureBroadcastReceiver() {
verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiverCaptor.capture(),
- anyObject());
+ mIntentFilterCaptor.capture());
mBroadcastReceiver = mBroadcastReceiverCaptor.getValue();
+ mIntentFilter = mIntentFilterCaptor.getValue();
+ assertEquals(2, mIntentFilter.countActions());
+ org.hamcrest.MatcherAssert.assertThat(() -> mIntentFilter.actionsIterator(),
+ containsInAnyOrder(ACTION_ENTER_CAR_MODE, ACTION_EXIT_CAR_MODE));
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 4eeb4acf18b8..01a1a3718765 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -17,6 +17,8 @@
package com.android.systemui.doze;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
+import static com.android.systemui.doze.DozeMachine.State.INITIALIZED;
+import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
@@ -133,7 +135,7 @@ public class DozeTriggersTest extends SysuiTestCase {
ArgumentCaptor<DozeHost.Callback> captor = ArgumentCaptor.forClass(DozeHost.Callback.class);
doAnswer(invocation -> null).when(mHost).addCallback(captor.capture());
- mTriggers.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
+ mTriggers.transitionTo(UNINITIALIZED, DozeMachine.State.INITIALIZED);
mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
clearInvocations(mMachine);
@@ -192,8 +194,21 @@ public class DozeTriggersTest extends SysuiTestCase {
}
@Test
+ public void transitionToDozeSuspendTriggers_disablesAllCallbacks() {
+ mTriggers.transitionTo(UNINITIALIZED, INITIALIZED);
+ when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_SUSPEND_TRIGGERS);
+
+ mTriggers.transitionTo(DozeMachine.State.INITIALIZED,
+ DozeMachine.State.DOZE_SUSPEND_TRIGGERS);
+
+ verify(mDockManager).removeListener(any());
+ verify(mBroadcastDispatcher).unregisterReceiver(any());
+ verify(mHost).removeCallback(any());
+ }
+
+ @Test
public void testDockEventListener_registerAndUnregister() {
- mTriggers.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
+ mTriggers.transitionTo(UNINITIALIZED, DozeMachine.State.INITIALIZED);
verify(mDockManager).addListener(any());
mTriggers.transitionTo(DozeMachine.State.DOZE, DozeMachine.State.FINISH);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt
index 8fd2d2f81dce..b97924107322 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt
@@ -57,11 +57,13 @@ class ColorSchemeTransitionTest : SysuiTestCase() {
private lateinit var animatingColorTransitionFactory: AnimatingColorTransitionFactory
@Mock private lateinit var mediaViewHolder: MediaViewHolder
+ @Mock private lateinit var gutsViewHolder: GutsViewHolder
@JvmField @Rule val mockitoRule = MockitoJUnit.rule()
@Before
fun setUp() {
+ whenever(mediaViewHolder.gutsViewHolder).thenReturn(gutsViewHolder)
animatingColorTransitionFactory = { _, _, _ -> mockAnimatingTransition }
whenever(extractColor.invoke(colorScheme)).thenReturn(TARGET_COLOR)
@@ -147,5 +149,6 @@ class ColorSchemeTransitionTest : SysuiTestCase() {
fun testColorSchemeTransition_update() {
colorSchemeTransition.updateColorScheme(colorScheme, true)
verify(mockAnimatingTransition, times(10)).updateColorScheme(colorScheme)
+ verify(gutsViewHolder).colorScheme = colorScheme
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index 241ed2443e6c..540f2a534854 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -58,6 +58,7 @@ import com.android.internal.logging.InstanceId
import com.android.systemui.ActivityIntentHelper
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.bluetooth.BroadcastDialogController
import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.media.MediaControlPanel.KEY_SMARTSPACE_APP_NAME
import com.android.systemui.media.dialog.MediaOutputDialogFactory
@@ -104,6 +105,7 @@ private const val SESSION_ARTIST = "SESSION_ARTIST"
private const val SESSION_TITLE = "SESSION_TITLE"
private const val DISABLED_DEVICE_NAME = "DISABLED_DEVICE_NAME"
private const val REC_APP_NAME = "REC APP NAME"
+private const val APP_NAME = "APP_NAME"
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -130,6 +132,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Mock private lateinit var mediaCarouselController: MediaCarouselController
@Mock private lateinit var falsingManager: FalsingManager
@Mock private lateinit var transitionParent: ViewGroup
+ @Mock private lateinit var broadcastDialogController: BroadcastDialogController
private lateinit var appIcon: ImageView
@Mock private lateinit var albumView: ImageView
private lateinit var titleText: TextView
@@ -160,8 +163,9 @@ public class MediaControlPanelTest : SysuiTestCase() {
private lateinit var dismissText: TextView
private lateinit var session: MediaSession
- private val device = MediaDeviceData(true, null, DEVICE_NAME)
- private val disabledDevice = MediaDeviceData(false, null, DISABLED_DEVICE_NAME)
+ private lateinit var device: MediaDeviceData
+ private val disabledDevice = MediaDeviceData(false, null, DISABLED_DEVICE_NAME, null,
+ showBroadcastButton = false)
private lateinit var mediaData: MediaData
private val clock = FakeSystemClock()
@Mock private lateinit var logger: MediaUiEventLogger
@@ -187,6 +191,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
private lateinit var recSubtitle1: TextView
private lateinit var recSubtitle2: TextView
private lateinit var recSubtitle3: TextView
+ private var shouldShowBroadcastButton: Boolean = false
@JvmField @Rule val mockito = MockitoJUnit.rule()
@@ -223,7 +228,8 @@ public class MediaControlPanelTest : SysuiTestCase() {
logger,
keyguardStateController,
activityIntentHelper,
- lockscreenUserManager) {
+ lockscreenUserManager,
+ broadcastDialogController) {
override fun loadAnimator(
animId: Int,
otionInterpolator: Interpolator,
@@ -236,28 +242,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
initGutsViewHolderMocks()
initMediaViewHolderMocks()
- // Create media session
- val metadataBuilder = MediaMetadata.Builder().apply {
- putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
- putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
- }
- val playbackBuilder = PlaybackState.Builder().apply {
- setState(PlaybackState.STATE_PAUSED, 6000L, 1f)
- setActions(PlaybackState.ACTION_PLAY)
- }
- session = MediaSession(context, SESSION_KEY).apply {
- setMetadata(metadataBuilder.build())
- setPlaybackState(playbackBuilder.build())
- }
- session.setActive(true)
-
- mediaData = MediaTestUtils.emptyMediaData.copy(
- artist = ARTIST,
- song = TITLE,
- packageName = PACKAGE,
- token = session.sessionToken,
- device = device,
- instanceId = instanceId)
+ initDeviceMediaData(false, DEVICE_NAME)
// Set up recommendation view
initRecommendationViewHolderMocks()
@@ -293,6 +278,34 @@ public class MediaControlPanelTest : SysuiTestCase() {
whenever(gutsViewHolder.dismissText).thenReturn(dismissText)
}
+ private fun initDeviceMediaData(shouldShowBroadcastButton: Boolean, name: String) {
+ device = MediaDeviceData(true, null, name, null,
+ showBroadcastButton = shouldShowBroadcastButton)
+
+ // Create media session
+ val metadataBuilder = MediaMetadata.Builder().apply {
+ putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
+ putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
+ }
+ val playbackBuilder = PlaybackState.Builder().apply {
+ setState(PlaybackState.STATE_PAUSED, 6000L, 1f)
+ setActions(PlaybackState.ACTION_PLAY)
+ }
+ session = MediaSession(context, SESSION_KEY).apply {
+ setMetadata(metadataBuilder.build())
+ setPlaybackState(playbackBuilder.build())
+ }
+ session.setActive(true)
+
+ mediaData = MediaTestUtils.emptyMediaData.copy(
+ artist = ARTIST,
+ song = TITLE,
+ packageName = PACKAGE,
+ token = session.sessionToken,
+ device = device,
+ instanceId = instanceId)
+ }
+
/**
* Initialize elements in media view holder
*/
@@ -1032,6 +1045,28 @@ public class MediaControlPanelTest : SysuiTestCase() {
assertThat(seamless.isEnabled()).isFalse()
}
+ @Test
+ fun bindBroadcastButton() {
+ initMediaViewHolderMocks()
+ initDeviceMediaData(true, APP_NAME)
+
+ val mockAvd0 = mock(AnimatedVectorDrawable::class.java)
+ whenever(mockAvd0.mutate()).thenReturn(mockAvd0)
+ val semanticActions0 = MediaButton(
+ playOrPause = MediaAction(mockAvd0, Runnable {}, "play", null)
+ )
+ val state = mediaData.copy(resumption = true, semanticActions = semanticActions0,
+ isPlaying = false)
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(state, PACKAGE)
+ assertThat(seamlessText.getText()).isEqualTo(APP_NAME)
+ assertThat(seamless.isEnabled()).isTrue()
+
+ seamless.callOnClick()
+
+ verify(logger).logOpenBroadcastDialog(anyInt(), eq(PACKAGE), eq(instanceId))
+ }
+
/* ***** Guts tests for the player ***** */
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
index 3e335c5163a9..04b93d79f83b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
@@ -79,7 +79,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
new ArrayList<>(), new ArrayList<>(), null, PACKAGE, null, null, null, true, null,
MediaData.PLAYBACK_LOCAL, false, KEY, false, false, false, 0L,
InstanceId.fakeInstanceId(-1), -1);
- mDeviceData = new MediaDeviceData(true, null, DEVICE_NAME);
+ mDeviceData = new MediaDeviceData(true, null, DEVICE_NAME, null, false);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 9a7b129f7597..1cce7cfb5b8a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -603,6 +603,7 @@ class MediaDataManagerTest : SysuiTestCase() {
.onSmartspaceMediaDataLoaded(anyObject(), anyObject(), anyBoolean())
}
+ @Ignore("b/229838140")
@Test
fun testMediaRecommendationDisabled_removesSmartspaceData() {
// GIVEN a media recommendation card is present
@@ -978,6 +979,26 @@ class MediaDataManagerTest : SysuiTestCase() {
anyBoolean())
}
+ @Test
+ fun testPlaybackStateChange_keyHasNullToken_doesNothing() {
+ // When we get an update that sets the data's token to null
+ whenever(controller.metadata).thenReturn(metadataBuilder.build())
+ addNotificationAndLoad()
+ val data = mediaDataCaptor.value
+ assertThat(data.resumption).isFalse()
+ mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(token = null))
+
+ // And then get a state update
+ val state = PlaybackState.Builder().build()
+ val callbackCaptor = argumentCaptor<(String, PlaybackState) -> Unit>()
+ verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor)
+
+ // Then no changes are made
+ callbackCaptor.value.invoke(KEY, state)
+ verify(listener, never()).onMediaDataLoaded(eq(KEY), any(), any(), anyBoolean(), anyInt(),
+ anyBoolean())
+ }
+
/**
* Helper function to add a media notification and capture the resulting MediaData
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
index 18ee79138b52..11fe87d363a0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
@@ -16,6 +16,10 @@
package com.android.systemui.media
+import android.bluetooth.BluetoothLeBroadcast
+import android.bluetooth.BluetoothLeBroadcastMetadata
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import android.media.MediaRouter2Manager
import android.media.RoutingSessionInfo
@@ -25,8 +29,12 @@ import android.media.session.MediaSession
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
+import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager
import com.android.settingslib.media.LocalMediaManager
import com.android.settingslib.media.MediaDevice
+import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionManager
@@ -42,6 +50,7 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.mock
@@ -57,6 +66,8 @@ private const val PACKAGE = "PKG"
private const val SESSION_KEY = "SESSION_KEY"
private const val DEVICE_NAME = "DEVICE_NAME"
private const val REMOTE_DEVICE_NAME = "REMOTE_DEVICE_NAME"
+private const val BROADCAST_APP_NAME = "BROADCAST_APP_NAME"
+private const val NORMAL_APP_NAME = "NORMAL_APP_NAME"
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -80,6 +91,12 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Mock private lateinit var controller: MediaController
@Mock private lateinit var playbackInfo: PlaybackInfo
@Mock private lateinit var configurationController: ConfigurationController
+ @Mock private lateinit var bluetoothLeBroadcast: BluetoothLeBroadcast
+ @Mock private lateinit var localBluetoothProfileManager: LocalBluetoothProfileManager
+ @Mock private lateinit var localBluetoothLeBroadcast: LocalBluetoothLeBroadcast
+ @Mock private lateinit var packageManager: PackageManager
+ @Mock private lateinit var applicationInfo: ApplicationInfo
+ private lateinit var localBluetoothManager: LocalBluetoothManager
private lateinit var session: MediaSession
private lateinit var mediaData: MediaData
@JvmField @Rule val mockito = MockitoJUnit.rule()
@@ -88,12 +105,15 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
fun setUp() {
fakeFgExecutor = FakeExecutor(FakeSystemClock())
fakeBgExecutor = FakeExecutor(FakeSystemClock())
+ localBluetoothManager = mDependency.injectMockDependency(LocalBluetoothManager::class.java)
manager = MediaDeviceManager(
+ context,
controllerFactory,
lmmFactory,
mr2,
muteAwaitFactory,
configurationController,
+ localBluetoothManager,
fakeFgExecutor,
fakeBgExecutor,
dumpster
@@ -116,6 +136,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
token = session.sessionToken)
whenever(controllerFactory.create(session.sessionToken))
.thenReturn(controller)
+ setupLeAudioConfiguration(false)
}
@After
@@ -459,7 +480,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Test
fun testRemotePlaybackDeviceOverride() {
whenever(route.name).thenReturn(DEVICE_NAME)
- val deviceData = MediaDeviceData(false, null, REMOTE_DEVICE_NAME, null)
+ val deviceData = MediaDeviceData(false, null, REMOTE_DEVICE_NAME, null,
+ showBroadcastButton = false)
val mediaDataWithDevice = mediaData.copy(device = deviceData)
// GIVEN media data that already has a device set
@@ -474,12 +496,95 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
verify(lmm, never()).registerCallback(any())
}
+ @Test
+ fun onBroadcastStarted_currentMediaDeviceDataIsBroadcasting() {
+ val broadcastCallback = setupBroadcastCallback()
+ setupLeAudioConfiguration(true)
+ setupBroadcastPackage(BROADCAST_APP_NAME)
+ broadcastCallback.onBroadcastStarted(1, 1)
+
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ fakeBgExecutor.runAllReady()
+ fakeFgExecutor.runAllReady()
+
+ val data = captureDeviceData(KEY)
+ assertThat(data.showBroadcastButton).isTrue()
+ assertThat(data.enabled).isTrue()
+ assertThat(data.name).isEqualTo(context.getString(
+ R.string.broadcasting_description_is_broadcasting))
+ }
+
+ @Test
+ fun onBroadcastStarted_currentMediaDeviceDataIsNotBroadcasting() {
+ val broadcastCallback = setupBroadcastCallback()
+ setupLeAudioConfiguration(true)
+ setupBroadcastPackage(NORMAL_APP_NAME)
+ broadcastCallback.onBroadcastStarted(1, 1)
+
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ fakeBgExecutor.runAllReady()
+ fakeFgExecutor.runAllReady()
+
+ val data = captureDeviceData(KEY)
+ assertThat(data.showBroadcastButton).isTrue()
+ assertThat(data.enabled).isTrue()
+ assertThat(data.name).isEqualTo(BROADCAST_APP_NAME)
+ }
+
+ @Test
+ fun onBroadcastStopped_bluetoothLeBroadcastIsDisabledAndBroadcastingButtonIsGone() {
+ val broadcastCallback = setupBroadcastCallback()
+ setupLeAudioConfiguration(false)
+ broadcastCallback.onBroadcastStopped(1, 1)
+
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ fakeBgExecutor.runAllReady()
+ fakeFgExecutor.runAllReady()
+
+ val data = captureDeviceData(KEY)
+ assertThat(data.showBroadcastButton).isFalse()
+ }
+
fun captureCallback(): LocalMediaManager.DeviceCallback {
val captor = ArgumentCaptor.forClass(LocalMediaManager.DeviceCallback::class.java)
verify(lmm).registerCallback(captor.capture())
return captor.getValue()
}
+ fun setupBroadcastCallback(): BluetoothLeBroadcast.Callback {
+ val callback: BluetoothLeBroadcast.Callback = object : BluetoothLeBroadcast.Callback {
+ override fun onBroadcastStarted(reason: Int, broadcastId: Int) {}
+ override fun onBroadcastStartFailed(reason: Int) {}
+ override fun onBroadcastStopped(reason: Int, broadcastId: Int) {}
+ override fun onBroadcastStopFailed(reason: Int) {}
+ override fun onPlaybackStarted(reason: Int, broadcastId: Int) {}
+ override fun onPlaybackStopped(reason: Int, broadcastId: Int) {}
+ override fun onBroadcastUpdated(reason: Int, broadcastId: Int) {}
+ override fun onBroadcastUpdateFailed(reason: Int, broadcastId: Int) {}
+ override fun onBroadcastMetadataChanged(broadcastId: Int,
+ metadata: BluetoothLeBroadcastMetadata) {}
+ }
+
+ bluetoothLeBroadcast.registerCallback(fakeFgExecutor, callback)
+ return callback;
+ }
+
+ fun setupLeAudioConfiguration(isLeAudio: Boolean) {
+ whenever(localBluetoothManager.profileManager).thenReturn(localBluetoothProfileManager)
+ whenever(localBluetoothProfileManager.leAudioBroadcastProfile)
+ .thenReturn(localBluetoothLeBroadcast)
+ whenever(localBluetoothLeBroadcast.isEnabled(any())).thenReturn(isLeAudio)
+ whenever(localBluetoothLeBroadcast.appSourceName).thenReturn(BROADCAST_APP_NAME)
+ }
+
+ fun setupBroadcastPackage(currentName: String) {
+ whenever(lmm.packageName).thenReturn(PACKAGE)
+ whenever(packageManager.getApplicationInfo(eq(PACKAGE), anyInt()))
+ .thenReturn(applicationInfo)
+ whenever(packageManager.getApplicationLabel(applicationInfo)).thenReturn(currentName)
+ context.setMockPackageManager(packageManager)
+ }
+
fun captureDeviceData(key: String, oldKey: String? = null): MediaDeviceData {
val captor = ArgumentCaptor.forClass(MediaDeviceData::class.java)
verify(listener).onMediaDeviceChanged(eq(key), eq(oldKey), captor.capture())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt
index ae58fe67da23..3d9ed5fe7f7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt
@@ -20,7 +20,8 @@ class MediaTestUtils {
device = null,
active = true,
resumeAction = null,
+ isPlaying = false,
instanceId = InstanceId.fakeInstanceId(-1),
appUid = -1)
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
index 49be669bb4a5..9e9cda843c8f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
@@ -178,8 +178,10 @@ class SeekBarObserverTest : SysuiTestCase() {
}
@Test
- fun seekBarProgress_enabled_timeViewsHaveTime() {
- val data = SeekBarViewModel.Progress(enabled = true, true, true, false, 3000, 120000)
+ fun seekBarProgress_enabledAndScrubbing_timeViewsHaveTime() {
+ val isEnabled = true
+ val isScrubbing = true
+ val data = SeekBarViewModel.Progress(isEnabled, true, true, isScrubbing, 3000, 120000)
observer.onChanged(data)
@@ -188,8 +190,22 @@ class SeekBarObserverTest : SysuiTestCase() {
}
@Test
- fun seekBarProgress_disabled_timeViewsEmpty() {
- val data = SeekBarViewModel.Progress(enabled = false, true, true, false, 3000, 120000)
+ fun seekBarProgress_disabledAndScrubbing_timeViewsEmpty() {
+ val isEnabled = false
+ val isScrubbing = true
+ val data = SeekBarViewModel.Progress(isEnabled, true, true, isScrubbing, 3000, 120000)
+
+ observer.onChanged(data)
+
+ assertThat(scrubbingElapsedTimeView.text).isEqualTo("")
+ assertThat(scrubbingTotalTimeView.text).isEqualTo("")
+ }
+
+ @Test
+ fun seekBarProgress_enabledAndNotScrubbing_timeViewsEmpty() {
+ val isEnabled = true
+ val isScrubbing = false
+ val data = SeekBarViewModel.Progress(isEnabled, true, true, isScrubbing, 3000, 120000)
observer.onChanged(data)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
index 890e4de118e3..63dca3bafc5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
@@ -69,7 +69,7 @@ public class ColorSchemeTest extends SysuiTestCase {
// Expressive applies hue rotations to the theme color. The input theme color has hue
// 117, ensuring the hue changed significantly is a strong signal styles are being applied.
ColorScheme colorScheme = new ColorScheme(wallpaperColors, false, Style.EXPRESSIVE);
- Assert.assertEquals(Cam.fromInt(colorScheme.getAccent1().get(6)).getHue(), 357.46, 0.1);
+ Assert.assertEquals(357.77, Cam.fromInt(colorScheme.getAccent1().get(6)).getHue(), 0.1);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitorTest.kt
new file mode 100644
index 000000000000..db96d5507ba1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitorTest.kt
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.privacy
+
+import android.app.AppOpsManager
+import android.content.pm.UserInfo
+import android.os.UserHandle
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.appops.AppOpItem
+import com.android.systemui.appops.AppOpsController
+import com.android.systemui.privacy.logging.PrivacyLogger
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+import org.hamcrest.Matchers.hasItem
+import org.hamcrest.Matchers.not
+import org.hamcrest.Matchers.nullValue
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertThat
+import org.junit.Assert.assertTrue
+import org.junit.Assert.assertFalse
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.atLeastOnce
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+@RunWithLooper
+class AppOpsPrivacyItemMonitorTest : SysuiTestCase() {
+
+ companion object {
+ val CURRENT_USER_ID = 1
+ val TEST_UID = CURRENT_USER_ID * UserHandle.PER_USER_RANGE
+ const val TEST_PACKAGE_NAME = "test"
+
+ fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
+ fun <T> eq(value: T): T = Mockito.eq(value) ?: value
+ fun <T> any(): T = Mockito.any<T>()
+ }
+
+ @Mock
+ private lateinit var appOpsController: AppOpsController
+
+ @Mock
+ private lateinit var callback: PrivacyItemMonitor.Callback
+
+ @Mock
+ private lateinit var userTracker: UserTracker
+
+ @Mock
+ private lateinit var privacyConfig: PrivacyConfig
+
+ @Mock
+ private lateinit var logger: PrivacyLogger
+
+ @Captor
+ private lateinit var argCaptorConfigCallback: ArgumentCaptor<PrivacyConfig.Callback>
+
+ @Captor
+ private lateinit var argCaptorCallback: ArgumentCaptor<AppOpsController.Callback>
+
+ private lateinit var appOpsPrivacyItemMonitor: AppOpsPrivacyItemMonitor
+ private lateinit var executor: FakeExecutor
+
+ fun createAppOpsPrivacyItemMonitor(): AppOpsPrivacyItemMonitor {
+ return AppOpsPrivacyItemMonitor(
+ appOpsController,
+ userTracker,
+ privacyConfig,
+ executor,
+ logger)
+ }
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ executor = FakeExecutor(FakeSystemClock())
+
+ // Listen to everything by default
+ `when`(privacyConfig.micCameraAvailable).thenReturn(true)
+ `when`(privacyConfig.locationAvailable).thenReturn(true)
+ `when`(userTracker.userProfiles).thenReturn(
+ listOf(UserInfo(CURRENT_USER_ID, TEST_PACKAGE_NAME, 0)))
+
+ appOpsPrivacyItemMonitor = createAppOpsPrivacyItemMonitor()
+ verify(privacyConfig).addCallback(capture(argCaptorConfigCallback))
+ }
+
+ @Test
+ fun testStartListeningAddsAppOpsCallback() {
+ appOpsPrivacyItemMonitor.startListening(callback)
+ executor.runAllReady()
+ verify(appOpsController).addCallback(eq(AppOpsPrivacyItemMonitor.OPS), any())
+ }
+
+ @Test
+ fun testStopListeningRemovesAppOpsCallback() {
+ appOpsPrivacyItemMonitor.startListening(callback)
+ executor.runAllReady()
+ verify(appOpsController, never()).removeCallback(any(), any())
+
+ appOpsPrivacyItemMonitor.stopListening()
+ executor.runAllReady()
+ verify(appOpsController).removeCallback(eq(AppOpsPrivacyItemMonitor.OPS), any())
+ }
+
+ @Test
+ fun testDistinctItems() {
+ doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, 0),
+ AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, 0)))
+ .`when`(appOpsController).getActiveAppOps(anyBoolean())
+
+ assertEquals(1, appOpsPrivacyItemMonitor.getActivePrivacyItems().size)
+ }
+
+ @Test
+ fun testSimilarItemsDifferentTimeStamp() {
+ doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, 0),
+ AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, 1)))
+ .`when`(appOpsController).getActiveAppOps(anyBoolean())
+
+ assertEquals(2, appOpsPrivacyItemMonitor.getActivePrivacyItems().size)
+ }
+
+ @Test
+ fun testRegisterUserTrackerCallback() {
+ appOpsPrivacyItemMonitor.startListening(callback)
+ executor.runAllReady()
+ verify(userTracker, atLeastOnce()).addCallback(
+ eq(appOpsPrivacyItemMonitor.userTrackerCallback), any())
+ verify(userTracker, never()).removeCallback(
+ eq(appOpsPrivacyItemMonitor.userTrackerCallback))
+ }
+
+ @Test
+ fun testUserTrackerCallback_userChanged() {
+ appOpsPrivacyItemMonitor.userTrackerCallback.onUserChanged(0, mContext)
+ executor.runAllReady()
+ verify(userTracker).userProfiles
+ }
+
+ @Test
+ fun testUserTrackerCallback_profilesChanged() {
+ appOpsPrivacyItemMonitor.userTrackerCallback.onProfilesChanged(emptyList())
+ executor.runAllReady()
+ verify(userTracker).userProfiles
+ }
+
+ @Test
+ fun testCallbackIsUpdated() {
+ doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOps(anyBoolean())
+ appOpsPrivacyItemMonitor.startListening(callback)
+ executor.runAllReady()
+ reset(callback)
+
+ verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
+ argCaptorCallback.value.onActiveStateChanged(0, TEST_UID, TEST_PACKAGE_NAME, true)
+ executor.runAllReady()
+ verify(callback).onPrivacyItemsChanged()
+ }
+
+ @Test
+ fun testRemoveCallback() {
+ doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOps(anyBoolean())
+ appOpsPrivacyItemMonitor.startListening(callback)
+ executor.runAllReady()
+ reset(callback)
+
+ verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
+ appOpsPrivacyItemMonitor.stopListening()
+ argCaptorCallback.value.onActiveStateChanged(0, TEST_UID, TEST_PACKAGE_NAME, true)
+ executor.runAllReady()
+ verify(callback, never()).onPrivacyItemsChanged()
+ }
+
+ @Test
+ fun testListShouldNotHaveNull() {
+ doReturn(listOf(AppOpItem(AppOpsManager.OP_ACTIVATE_VPN, TEST_UID, TEST_PACKAGE_NAME, 0),
+ AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, 0)))
+ .`when`(appOpsController).getActiveAppOps(anyBoolean())
+
+ assertThat(appOpsPrivacyItemMonitor.getActivePrivacyItems(), not(hasItem(nullValue())))
+ }
+
+ @Test
+ fun testNotListeningWhenIndicatorsDisabled() {
+ changeMicCamera(false)
+ changeLocation(false)
+
+ appOpsPrivacyItemMonitor.startListening(callback)
+ executor.runAllReady()
+ verify(appOpsController, never()).addCallback(eq(AppOpsPrivacyItemMonitor.OPS), any())
+ }
+
+ @Test
+ fun testNotSendingLocationWhenLocationDisabled() {
+ changeLocation(false)
+ executor.runAllReady()
+
+ doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, 0),
+ AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, 0)))
+ .`when`(appOpsController).getActiveAppOps(anyBoolean())
+
+ val privacyItems = appOpsPrivacyItemMonitor.getActivePrivacyItems()
+ assertEquals(1, privacyItems.size)
+ assertEquals(PrivacyType.TYPE_CAMERA, privacyItems[0].privacyType)
+ }
+
+ @Test
+ fun testNotUpdated_LocationChangeWhenLocationDisabled() {
+ doReturn(listOf(
+ AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, 0)))
+ .`when`(appOpsController).getActiveAppOps(anyBoolean())
+
+ appOpsPrivacyItemMonitor.startListening(callback)
+ changeLocation(false)
+ executor.runAllReady()
+ reset(callback) // Clean callback
+
+ verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
+ argCaptorCallback.value.onActiveStateChanged(
+ AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true)
+
+ verify(callback, never()).onPrivacyItemsChanged()
+ }
+
+ @Test
+ fun testLogActiveChanged() {
+ appOpsPrivacyItemMonitor.startListening(callback)
+ executor.runAllReady()
+
+ verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
+ argCaptorCallback.value.onActiveStateChanged(
+ AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true)
+
+ verify(logger).logUpdatedItemFromAppOps(
+ AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true)
+ }
+
+ @Test
+ fun testListRequestedShowPaused() {
+ appOpsPrivacyItemMonitor.getActivePrivacyItems()
+ verify(appOpsController).getActiveAppOps(true)
+ }
+
+ @Test
+ fun testListFilterCurrentUser() {
+ val otherUser = CURRENT_USER_ID + 1
+ val otherUserUid = otherUser * UserHandle.PER_USER_RANGE
+ `when`(userTracker.userProfiles)
+ .thenReturn(listOf(UserInfo(otherUser, TEST_PACKAGE_NAME, 0)))
+
+ doReturn(listOf(
+ AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, 0),
+ AppOpItem(AppOpsManager.OP_CAMERA, otherUserUid, TEST_PACKAGE_NAME, 0))
+ ).`when`(appOpsController).getActiveAppOps(anyBoolean())
+
+ appOpsPrivacyItemMonitor.userTrackerCallback.onUserChanged(otherUser, mContext)
+ executor.runAllReady()
+
+ appOpsPrivacyItemMonitor.startListening(callback)
+ executor.runAllReady()
+
+ val privacyItems = appOpsPrivacyItemMonitor.getActivePrivacyItems()
+
+ assertEquals(1, privacyItems.size)
+ assertEquals(PrivacyType.TYPE_CAMERA, privacyItems[0].privacyType)
+ assertEquals(otherUserUid, privacyItems[0].application.uid)
+ }
+
+ @Test
+ fun testAlwaysGetPhoneCameraOps() {
+ val otherUser = CURRENT_USER_ID + 1
+ `when`(userTracker.userProfiles)
+ .thenReturn(listOf(UserInfo(otherUser, TEST_PACKAGE_NAME, 0)))
+
+ doReturn(listOf(
+ AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, 0),
+ AppOpItem(AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, 0),
+ AppOpItem(AppOpsManager.OP_PHONE_CALL_CAMERA, TEST_UID, TEST_PACKAGE_NAME, 0))
+ ).`when`(appOpsController).getActiveAppOps(anyBoolean())
+
+ appOpsPrivacyItemMonitor.userTrackerCallback.onUserChanged(otherUser, mContext)
+ executor.runAllReady()
+
+ appOpsPrivacyItemMonitor.startListening(callback)
+ executor.runAllReady()
+
+ val privacyItems = appOpsPrivacyItemMonitor.getActivePrivacyItems()
+
+ assertEquals(1, privacyItems.size)
+ assertEquals(PrivacyType.TYPE_CAMERA, privacyItems[0].privacyType)
+ }
+
+ @Test
+ fun testAlwaysGetPhoneMicOps() {
+ val otherUser = CURRENT_USER_ID + 1
+ `when`(userTracker.userProfiles)
+ .thenReturn(listOf(UserInfo(otherUser, TEST_PACKAGE_NAME, 0)))
+
+ doReturn(listOf(
+ AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, 0),
+ AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, 0),
+ AppOpItem(AppOpsManager.OP_PHONE_CALL_MICROPHONE, TEST_UID, TEST_PACKAGE_NAME, 0))
+ ).`when`(appOpsController).getActiveAppOps(anyBoolean())
+
+ appOpsPrivacyItemMonitor.userTrackerCallback.onUserChanged(otherUser, mContext)
+ executor.runAllReady()
+
+ appOpsPrivacyItemMonitor.startListening(callback)
+ executor.runAllReady()
+
+ val privacyItems = appOpsPrivacyItemMonitor.getActivePrivacyItems()
+
+ assertEquals(1, privacyItems.size)
+ assertEquals(PrivacyType.TYPE_MICROPHONE, privacyItems[0].privacyType)
+ }
+
+ @Test
+ fun testDisabledAppOpIsPaused() {
+ val item = AppOpItem(AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, 0)
+ item.isDisabled = true
+ `when`(appOpsController.getActiveAppOps(anyBoolean())).thenReturn(listOf(item))
+
+ val privacyItems = appOpsPrivacyItemMonitor.getActivePrivacyItems()
+ assertEquals(1, privacyItems.size)
+ assertTrue(privacyItems[0].paused)
+ }
+
+ @Test
+ fun testEnabledAppOpIsNotPaused() {
+ val item = AppOpItem(AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, 0)
+ `when`(appOpsController.getActiveAppOps(anyBoolean())).thenReturn(listOf(item))
+
+ val privacyItems = appOpsPrivacyItemMonitor.getActivePrivacyItems()
+ assertEquals(1, privacyItems.size)
+ assertFalse(privacyItems[0].paused)
+ }
+
+ private fun changeMicCamera(value: Boolean) {
+ `when`(privacyConfig.micCameraAvailable).thenReturn(value)
+ argCaptorConfigCallback.value.onFlagMicCameraChanged(value)
+ }
+
+ private fun changeLocation(value: Boolean) {
+ `when`(privacyConfig.locationAvailable).thenReturn(value)
+ argCaptorConfigCallback.value.onFlagLocationChanged(value)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyConfigFlagsTest.kt
index 2a8611f60a9f..272f149f379b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyConfigFlagsTest.kt
@@ -21,10 +21,7 @@ import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags
import com.android.systemui.SysuiTestCase
-import com.android.systemui.appops.AppOpsController
import com.android.systemui.dump.DumpManager
-import com.android.systemui.privacy.logging.PrivacyLogger
-import com.android.systemui.settings.UserTracker
import com.android.systemui.util.DeviceConfigProxy
import com.android.systemui.util.DeviceConfigProxyFake
import com.android.systemui.util.concurrency.FakeExecutor
@@ -34,9 +31,7 @@ import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
import org.mockito.Mock
-import org.mockito.Mockito
import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
@@ -44,40 +39,28 @@ import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@SmallTest
-class PrivacyItemControllerFlagsTest : SysuiTestCase() {
+class PrivacyConfigFlagsTest : SysuiTestCase() {
companion object {
- fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
- fun <T> eq(value: T): T = Mockito.eq(value) ?: value
- fun <T> any(): T = Mockito.any<T>()
-
private const val MIC_CAMERA = SystemUiDeviceConfigFlags.PROPERTY_MIC_CAMERA_ENABLED
private const val LOCATION = SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_ENABLED
+ private const val MEDIA_PROJECTION =
+ SystemUiDeviceConfigFlags.PROPERTY_MEDIA_PROJECTION_INDICATORS_ENABLED
}
+ private lateinit var privacyConfig: PrivacyConfig
+
@Mock
- private lateinit var appOpsController: AppOpsController
- @Mock
- private lateinit var callback: PrivacyItemController.Callback
+ private lateinit var callback: PrivacyConfig.Callback
@Mock
private lateinit var dumpManager: DumpManager
- @Mock
- private lateinit var userTracker: UserTracker
- @Mock
- private lateinit var logger: PrivacyLogger
- private lateinit var privacyItemController: PrivacyItemController
private lateinit var executor: FakeExecutor
private lateinit var deviceConfigProxy: DeviceConfigProxy
- fun createPrivacyItemController(): PrivacyItemController {
- return PrivacyItemController(
- appOpsController,
- executor,
+ fun createPrivacyConfig(): PrivacyConfig {
+ return PrivacyConfig(
executor,
deviceConfigProxy,
- userTracker,
- logger,
- FakeSystemClock(),
dumpManager)
}
@@ -87,15 +70,15 @@ class PrivacyItemControllerFlagsTest : SysuiTestCase() {
executor = FakeExecutor(FakeSystemClock())
deviceConfigProxy = DeviceConfigProxyFake()
- privacyItemController = createPrivacyItemController()
- privacyItemController.addCallback(callback)
+ privacyConfig = createPrivacyConfig()
+ privacyConfig.addCallback(callback)
executor.runAllReady()
}
@Test
fun testMicCameraListeningByDefault() {
- assertTrue(privacyItemController.micCameraAvailable)
+ assertTrue(privacyConfig.micCameraAvailable)
}
@Test
@@ -105,82 +88,55 @@ class PrivacyItemControllerFlagsTest : SysuiTestCase() {
verify(callback).onFlagMicCameraChanged(false)
- assertFalse(privacyItemController.micCameraAvailable)
- }
-
- @Test
- fun testLocationChanged() {
- changeLocation(true)
- executor.runAllReady()
-
- verify(callback).onFlagLocationChanged(true)
- assertTrue(privacyItemController.locationAvailable)
- }
-
- @Test
- fun testBothChanged() {
- changeAll(true)
- changeMicCamera(false)
- executor.runAllReady()
-
- verify(callback, atLeastOnce()).onFlagLocationChanged(true)
- verify(callback, atLeastOnce()).onFlagMicCameraChanged(false)
-
- assertTrue(privacyItemController.locationAvailable)
- assertFalse(privacyItemController.micCameraAvailable)
+ assertFalse(privacyConfig.micCameraAvailable)
}
@Test
- fun testAll_listeningToAll() {
- changeAll(true)
+ fun testMediaProjectionChanged() {
+ changeMediaProjection(false) // default is true
executor.runAllReady()
- verify(appOpsController).addCallback(eq(PrivacyItemController.OPS), any())
- }
-
- @Test
- fun testMicCamera_listening() {
- changeMicCamera(true)
- executor.runAllReady()
+ verify(callback).onFlagMediaProjectionChanged(false)
- verify(appOpsController).addCallback(eq(PrivacyItemController.OPS), any())
+ assertFalse(privacyConfig.mediaProjectionAvailable)
}
@Test
- fun testLocation_listening() {
+ fun testLocationChanged() {
changeLocation(true)
executor.runAllReady()
- verify(appOpsController).addCallback(eq(PrivacyItemController.OPS), any())
+ verify(callback).onFlagLocationChanged(true)
+ assertTrue(privacyConfig.locationAvailable)
}
@Test
- fun testAllFalse_notListening() {
- changeAll(true)
- executor.runAllReady()
- changeAll(false)
+ fun testMicCamAndLocationChanged() {
+ changeLocation(true)
changeMicCamera(false)
executor.runAllReady()
- verify(appOpsController).removeCallback(any(), any())
+ verify(callback, atLeastOnce()).onFlagLocationChanged(true)
+ verify(callback, atLeastOnce()).onFlagMicCameraChanged(false)
+
+ assertTrue(privacyConfig.locationAvailable)
+ assertFalse(privacyConfig.micCameraAvailable)
}
@Test
- fun testMicDeleted_stillListening() {
+ fun testMicDeleted_stillAvailable() {
changeMicCamera(true)
executor.runAllReady()
changeMicCamera(null)
executor.runAllReady()
- verify(appOpsController, never()).removeCallback(any(), any())
+ verify(callback, never()).onFlagMicCameraChanged(false)
+ assertTrue(privacyConfig.micCameraAvailable)
}
private fun changeMicCamera(value: Boolean?) = changeProperty(MIC_CAMERA, value)
private fun changeLocation(value: Boolean?) = changeProperty(LOCATION, value)
- private fun changeAll(value: Boolean?) {
- changeMicCamera(value)
- changeLocation(value)
- }
+ private fun changeMediaProjection(value: Boolean?) = changeProperty(MEDIA_PROJECTION, value)
private fun changeProperty(name: String, value: Boolean?) {
deviceConfigProxy.setProperty(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
index e4d7b1b7d451..d56363231827 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
@@ -17,36 +17,24 @@
package com.android.systemui.privacy
import android.app.ActivityManager
-import android.app.AppOpsManager
-import android.content.pm.UserInfo
import android.os.UserHandle
-import android.provider.DeviceConfig
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags
import com.android.systemui.SysuiTestCase
-import com.android.systemui.appops.AppOpItem
-import com.android.systemui.appops.AppOpsController
import com.android.systemui.dump.DumpManager
import com.android.systemui.privacy.logging.PrivacyLogger
-import com.android.systemui.settings.UserTracker
import com.android.systemui.util.DeviceConfigProxy
import com.android.systemui.util.DeviceConfigProxyFake
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.time.FakeSystemClock
-import org.hamcrest.Matchers.hasItem
-import org.hamcrest.Matchers.not
-import org.hamcrest.Matchers.nullValue
import org.junit.Assert.assertEquals
-import org.junit.Assert.assertThat
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyList
import org.mockito.Captor
import org.mockito.Mock
@@ -71,20 +59,18 @@ class PrivacyItemControllerTest : SysuiTestCase() {
val TEST_UID = CURRENT_USER_ID * UserHandle.PER_USER_RANGE
const val TEST_PACKAGE_NAME = "test"
- private const val LOCATION_INDICATOR =
- SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_ENABLED
- private const val MIC_CAMERA = SystemUiDeviceConfigFlags.PROPERTY_MIC_CAMERA_ENABLED
fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
- fun <T> eq(value: T): T = Mockito.eq(value) ?: value
fun <T> any(): T = Mockito.any<T>()
}
@Mock
- private lateinit var appOpsController: AppOpsController
- @Mock
private lateinit var callback: PrivacyItemController.Callback
@Mock
- private lateinit var userTracker: UserTracker
+ private lateinit var privacyConfig: PrivacyConfig
+ @Mock
+ private lateinit var privacyItemMonitor: PrivacyItemMonitor
+ @Mock
+ private lateinit var privacyItemMonitor2: PrivacyItemMonitor
@Mock
private lateinit var dumpManager: DumpManager
@Mock
@@ -92,23 +78,21 @@ class PrivacyItemControllerTest : SysuiTestCase() {
@Captor
private lateinit var argCaptor: ArgumentCaptor<List<PrivacyItem>>
@Captor
- private lateinit var argCaptorCallback: ArgumentCaptor<AppOpsController.Callback>
+ private lateinit var argCaptorCallback: ArgumentCaptor<PrivacyItemMonitor.Callback>
+ @Captor
+ private lateinit var argCaptorConfigCallback: ArgumentCaptor<PrivacyConfig.Callback>
private lateinit var privacyItemController: PrivacyItemController
private lateinit var executor: FakeExecutor
private lateinit var fakeClock: FakeSystemClock
private lateinit var deviceConfigProxy: DeviceConfigProxy
- private val elapsedTime: Long
- get() = fakeClock.elapsedRealtime()
-
fun createPrivacyItemController(): PrivacyItemController {
return PrivacyItemController(
- appOpsController,
executor,
executor,
- deviceConfigProxy,
- userTracker,
+ privacyConfig,
+ setOf(privacyItemMonitor, privacyItemMonitor2),
logger,
fakeClock,
dumpManager)
@@ -120,83 +104,81 @@ class PrivacyItemControllerTest : SysuiTestCase() {
fakeClock = FakeSystemClock()
executor = FakeExecutor(fakeClock)
deviceConfigProxy = DeviceConfigProxyFake()
-
- // Listen to everything by default
- changeMicCamera(true)
- changeLocation(true)
-
- `when`(userTracker.userProfiles).thenReturn(listOf(UserInfo(CURRENT_USER_ID, "", 0)))
-
privacyItemController = createPrivacyItemController()
}
@Test
- fun testSetListeningTrueByAddingCallback() {
+ fun testStartListeningByAddingCallback() {
privacyItemController.addCallback(callback)
executor.runAllReady()
- verify(appOpsController).addCallback(eq(PrivacyItemController.OPS),
- any())
+ verify(privacyItemMonitor).startListening(any())
+ verify(privacyItemMonitor2).startListening(any())
verify(callback).onPrivacyItemsChanged(anyList())
}
@Test
- fun testSetListeningFalseByRemovingLastCallback() {
+ fun testStopListeningByRemovingLastCallback() {
privacyItemController.addCallback(callback)
executor.runAllReady()
- verify(appOpsController, never()).removeCallback(any(),
- any())
+ verify(privacyItemMonitor, never()).stopListening()
privacyItemController.removeCallback(callback)
executor.runAllReady()
- verify(appOpsController).removeCallback(eq(PrivacyItemController.OPS),
- any())
+ verify(privacyItemMonitor).stopListening()
+ verify(privacyItemMonitor2).stopListening()
verify(callback).onPrivacyItemsChanged(emptyList())
}
@Test
- fun testDistinctItems() {
- doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 0),
- AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 0)))
- .`when`(appOpsController).getActiveAppOps(anyBoolean())
+ fun testPrivacyItemsAggregated() {
+ val item1 = PrivacyItem(PrivacyType.TYPE_CAMERA,
+ PrivacyApplication(TEST_PACKAGE_NAME, TEST_UID), 0)
+ val item2 = PrivacyItem(PrivacyType.TYPE_MICROPHONE,
+ PrivacyApplication(TEST_PACKAGE_NAME, TEST_UID), 1)
+ doReturn(listOf(item1))
+ .`when`(privacyItemMonitor).getActivePrivacyItems()
+ doReturn(listOf(item2))
+ .`when`(privacyItemMonitor2).getActivePrivacyItems()
privacyItemController.addCallback(callback)
executor.runAllReady()
verify(callback).onPrivacyItemsChanged(capture(argCaptor))
- assertEquals(1, argCaptor.value.size)
+ assertEquals(2, argCaptor.value.size)
+ assertTrue(argCaptor.value.contains(item1))
+ assertTrue(argCaptor.value.contains(item2))
}
@Test
- fun testSimilarItemsDifferentTimeStamp() {
- doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 0),
- AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 1)))
- .`when`(appOpsController).getActiveAppOps(anyBoolean())
+ fun testDistinctItems() {
+ doReturn(listOf(
+ PrivacyItem(PrivacyType.TYPE_CAMERA,
+ PrivacyApplication(TEST_PACKAGE_NAME, TEST_UID), 0),
+ PrivacyItem(PrivacyType.TYPE_CAMERA,
+ PrivacyApplication(TEST_PACKAGE_NAME, TEST_UID), 0)))
+ .`when`(privacyItemMonitor).getActivePrivacyItems()
+ doReturn(listOf(
+ PrivacyItem(PrivacyType.TYPE_CAMERA,
+ PrivacyApplication(TEST_PACKAGE_NAME, TEST_UID), 0)))
+ .`when`(privacyItemMonitor2).getActivePrivacyItems()
privacyItemController.addCallback(callback)
executor.runAllReady()
verify(callback).onPrivacyItemsChanged(capture(argCaptor))
- assertEquals(2, argCaptor.value.size)
- }
-
- @Test
- fun testRegisterCallback() {
- privacyItemController.addCallback(callback)
- executor.runAllReady()
- verify(userTracker, atLeastOnce()).addCallback(
- eq(privacyItemController.userTrackerCallback), any())
- verify(userTracker, never()).removeCallback(eq(privacyItemController.userTrackerCallback))
+ assertEquals(1, argCaptor.value.size)
}
@Test
- fun testCallback_userChanged() {
- privacyItemController.userTrackerCallback.onUserChanged(0, mContext)
- executor.runAllReady()
- verify(userTracker).userProfiles
- }
+ fun testSimilarItemsDifferentTimeStamp() {
+ doReturn(listOf(
+ PrivacyItem(PrivacyType.TYPE_CAMERA,
+ PrivacyApplication(TEST_PACKAGE_NAME, TEST_UID), 0),
+ PrivacyItem(PrivacyType.TYPE_CAMERA,
+ PrivacyApplication(TEST_PACKAGE_NAME, TEST_UID), 1)))
+ .`when`(privacyItemMonitor).getActivePrivacyItems()
- @Test
- fun testReceiver_profilesChanged() {
- privacyItemController.userTrackerCallback.onProfilesChanged(emptyList())
+ privacyItemController.addCallback(callback)
executor.runAllReady()
- verify(userTracker).userProfiles
+ verify(callback).onPrivacyItemsChanged(capture(argCaptor))
+ assertEquals(2, argCaptor.value.size)
}
@Test
@@ -215,7 +197,7 @@ class PrivacyItemControllerTest : SysuiTestCase() {
@Test
fun testMultipleCallbacksAreUpdated() {
- doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOps(anyBoolean())
+ doReturn(emptyList<PrivacyItem>()).`when`(privacyItemMonitor).getActivePrivacyItems()
val otherCallback = mock(PrivacyItemController.Callback::class.java)
privacyItemController.addCallback(callback)
@@ -224,8 +206,8 @@ class PrivacyItemControllerTest : SysuiTestCase() {
reset(callback)
reset(otherCallback)
- verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
- argCaptorCallback.value.onActiveStateChanged(0, TEST_UID, "", true)
+ verify(privacyItemMonitor).startListening(capture(argCaptorCallback))
+ argCaptorCallback.value.onPrivacyItemsChanged()
executor.runAllReady()
verify(callback).onPrivacyItemsChanged(anyList())
verify(otherCallback).onPrivacyItemsChanged(anyList())
@@ -233,7 +215,7 @@ class PrivacyItemControllerTest : SysuiTestCase() {
@Test
fun testRemoveCallback() {
- doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOps(anyBoolean())
+ doReturn(emptyList<PrivacyItem>()).`when`(privacyItemMonitor).getActivePrivacyItems()
val otherCallback = mock(PrivacyItemController.Callback::class.java)
privacyItemController.addCallback(callback)
privacyItemController.addCallback(otherCallback)
@@ -242,32 +224,18 @@ class PrivacyItemControllerTest : SysuiTestCase() {
reset(callback)
reset(otherCallback)
- verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
+ verify(privacyItemMonitor).startListening(capture(argCaptorCallback))
privacyItemController.removeCallback(callback)
- argCaptorCallback.value.onActiveStateChanged(0, TEST_UID, "", true)
+ argCaptorCallback.value.onPrivacyItemsChanged()
executor.runAllReady()
verify(callback, never()).onPrivacyItemsChanged(anyList())
verify(otherCallback).onPrivacyItemsChanged(anyList())
}
@Test
- fun testListShouldNotHaveNull() {
- doReturn(listOf(AppOpItem(AppOpsManager.OP_ACTIVATE_VPN, TEST_UID, "", 0),
- AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, "", 0)))
- .`when`(appOpsController).getActiveAppOps(anyBoolean())
- privacyItemController.addCallback(callback)
- executor.runAllReady()
- executor.runAllReady()
-
- verify(callback).onPrivacyItemsChanged(capture(argCaptor))
- assertEquals(1, argCaptor.value.size)
- assertThat(argCaptor.value, not(hasItem(nullValue())))
- }
-
- @Test
fun testListShouldBeCopy() {
val list = listOf(PrivacyItem(PrivacyType.TYPE_CAMERA,
- PrivacyApplication("", TEST_UID), 0))
+ PrivacyApplication(TEST_PACKAGE_NAME, TEST_UID), 0))
privacyItemController.privacyList = list
val privacyList = privacyItemController.privacyList
assertEquals(list, privacyList)
@@ -275,174 +243,35 @@ class PrivacyItemControllerTest : SysuiTestCase() {
}
@Test
- fun testNotListeningWhenIndicatorsDisabled() {
- changeLocation(false)
- changeMicCamera(false)
- privacyItemController.addCallback(callback)
- executor.runAllReady()
- verify(appOpsController, never()).addCallback(eq(PrivacyItemController.OPS),
- any())
- }
-
- @Test
- fun testNotSendingLocationWhenOnlyMicCamera() {
- changeLocation(false)
- changeMicCamera(true)
- executor.runAllReady()
-
- doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 0),
- AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, "", 0)))
- .`when`(appOpsController).getActiveAppOps(anyBoolean())
-
- privacyItemController.addCallback(callback)
- executor.runAllReady()
-
- verify(callback).onPrivacyItemsChanged(capture(argCaptor))
-
- assertEquals(1, argCaptor.value.size)
- assertEquals(PrivacyType.TYPE_CAMERA, argCaptor.value[0].privacyType)
- }
-
- @Test
- fun testNotUpdated_LocationChangeWhenOnlyMicCamera() {
- doReturn(listOf(AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, "", 0)))
- .`when`(appOpsController).getActiveAppOps(anyBoolean())
-
- privacyItemController.addCallback(callback)
- changeLocation(false)
- changeMicCamera(true)
- executor.runAllReady()
- reset(callback) // Clean callback
-
- verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
- argCaptorCallback.value.onActiveStateChanged(
- AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true)
-
- verify(callback, never()).onPrivacyItemsChanged(any())
- }
-
- @Test
- fun testLogActiveChanged() {
- privacyItemController.addCallback(callback)
- executor.runAllReady()
-
- verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
- argCaptorCallback.value.onActiveStateChanged(
- AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true)
-
- verify(logger).logUpdatedItemFromAppOps(
- AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true)
- }
-
- @Test
fun testLogListUpdated() {
- doReturn(listOf(
- AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, 0))
- ).`when`(appOpsController).getActiveAppOps(anyBoolean())
-
- privacyItemController.addCallback(callback)
- executor.runAllReady()
-
- verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
- argCaptorCallback.value.onActiveStateChanged(
- AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true)
- executor.runAllReady()
-
- val expected = PrivacyItem(
+ val privacyItem = PrivacyItem(
PrivacyType.TYPE_LOCATION,
PrivacyApplication(TEST_PACKAGE_NAME, TEST_UID),
0
)
- val captor = argumentCaptor<List<PrivacyItem>>()
- verify(logger, atLeastOnce()).logRetrievedPrivacyItemsList(capture(captor))
- // Let's look at the last log
- val values = captor.allValues
- assertTrue(values[values.size - 1].contains(expected))
- }
-
- @Test
- fun testListRequestedShowPaused() {
- privacyItemController.addCallback(callback)
- executor.runAllReady()
- verify(appOpsController).getActiveAppOps(true)
- }
-
- @Test
- fun testListFilterCurrentUser() {
- val otherUser = CURRENT_USER_ID + 1
- val otherUserUid = otherUser * UserHandle.PER_USER_RANGE
- `when`(userTracker.userProfiles).thenReturn(listOf(UserInfo(otherUser, "", 0)))
-
- doReturn(listOf(
- AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, 0),
- AppOpItem(AppOpsManager.OP_CAMERA, otherUserUid, TEST_PACKAGE_NAME, 0))
- ).`when`(appOpsController).getActiveAppOps(anyBoolean())
-
- privacyItemController.userTrackerCallback.onUserChanged(otherUser, mContext)
- executor.runAllReady()
+ doReturn(listOf(privacyItem)).`when`(privacyItemMonitor).getActivePrivacyItems()
privacyItemController.addCallback(callback)
executor.runAllReady()
- verify(callback).onPrivacyItemsChanged(capture(argCaptor))
-
- assertEquals(1, argCaptor.value.size)
- assertEquals(PrivacyType.TYPE_CAMERA, argCaptor.value[0].privacyType)
- assertEquals(otherUserUid, argCaptor.value[0].application.uid)
- }
-
- @Test
- fun testAlwaysGetPhoneCameraOps() {
- val otherUser = CURRENT_USER_ID + 1
- `when`(userTracker.userProfiles).thenReturn(listOf(UserInfo(otherUser, "", 0)))
-
- doReturn(listOf(
- AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, 0),
- AppOpItem(AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, 0),
- AppOpItem(AppOpsManager.OP_PHONE_CALL_CAMERA, TEST_UID, TEST_PACKAGE_NAME, 0))
- ).`when`(appOpsController).getActiveAppOps(anyBoolean())
-
- privacyItemController.userTrackerCallback.onUserChanged(otherUser, mContext)
- executor.runAllReady()
-
- privacyItemController.addCallback(callback)
- executor.runAllReady()
-
- verify(callback).onPrivacyItemsChanged(capture(argCaptor))
-
- assertEquals(1, argCaptor.value.size)
- assertEquals(PrivacyType.TYPE_CAMERA, argCaptor.value[0].privacyType)
- }
-
- @Test
- fun testAlwaysGetPhoneMicOps() {
- val otherUser = CURRENT_USER_ID + 1
- `when`(userTracker.userProfiles).thenReturn(listOf(UserInfo(otherUser, "", 0)))
-
- doReturn(listOf(
- AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, 0),
- AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, 0),
- AppOpItem(AppOpsManager.OP_PHONE_CALL_MICROPHONE, TEST_UID, TEST_PACKAGE_NAME, 0))
- ).`when`(appOpsController).getActiveAppOps(anyBoolean())
-
- privacyItemController.userTrackerCallback.onUserChanged(otherUser, mContext)
+ verify(privacyItemMonitor).startListening(capture(argCaptorCallback))
+ argCaptorCallback.value.onPrivacyItemsChanged()
executor.runAllReady()
- privacyItemController.addCallback(callback)
- executor.runAllReady()
-
- verify(callback).onPrivacyItemsChanged(capture(argCaptor))
-
- assertEquals(1, argCaptor.value.size)
- assertEquals(PrivacyType.TYPE_MICROPHONE, argCaptor.value[0].privacyType)
+ val captor = argumentCaptor<List<PrivacyItem>>()
+ verify(logger, atLeastOnce()).logRetrievedPrivacyItemsList(capture(captor))
+ // Let's look at the last log
+ val values = captor.allValues
+ assertTrue(values[values.size - 1].contains(privacyItem))
}
@Test
fun testPassageOfTimeDoesNotRemoveIndicators() {
doReturn(listOf(
- AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, elapsedTime)
- )).`when`(appOpsController).getActiveAppOps(anyBoolean())
+ PrivacyItem(PrivacyType.TYPE_CAMERA,
+ PrivacyApplication(TEST_PACKAGE_NAME, TEST_UID), 0)
+ )).`when`(privacyItemMonitor).getActivePrivacyItems()
privacyItemController.addCallback(callback)
@@ -457,18 +286,18 @@ class PrivacyItemControllerTest : SysuiTestCase() {
fun testNotHeldAfterTimeIsOff() {
// Start with some element at time 0
doReturn(listOf(
- AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, elapsedTime)
- )).`when`(appOpsController).getActiveAppOps(anyBoolean())
+ PrivacyItem(PrivacyType.TYPE_CAMERA,
+ PrivacyApplication(TEST_PACKAGE_NAME, TEST_UID), 0)
+ )).`when`(privacyItemMonitor).getActivePrivacyItems()
privacyItemController.addCallback(callback)
executor.runAllReady()
// Then remove it at time HOLD + 1
- doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOps(anyBoolean())
+ doReturn(emptyList<PrivacyItem>()).`when`(privacyItemMonitor).getActivePrivacyItems()
fakeClock.advanceTime(PrivacyItemController.TIME_TO_HOLD_INDICATORS + 1)
- verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
- argCaptorCallback.value.onActiveStateChanged(
- AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, false)
+ verify(privacyItemMonitor).startListening(capture(argCaptorCallback))
+ argCaptorCallback.value.onPrivacyItemsChanged()
executor.runAllReady()
// See it's not there
@@ -478,20 +307,21 @@ class PrivacyItemControllerTest : SysuiTestCase() {
@Test
fun testElementNotRemovedBeforeHoldTime() {
- // Start with some element at time 0
+ // Start with some element at current time
doReturn(listOf(
- AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, elapsedTime)
- )).`when`(appOpsController).getActiveAppOps(anyBoolean())
+ PrivacyItem(PrivacyType.TYPE_CAMERA,
+ PrivacyApplication(TEST_PACKAGE_NAME, TEST_UID),
+ fakeClock.elapsedRealtime())
+ )).`when`(privacyItemMonitor).getActivePrivacyItems()
privacyItemController.addCallback(callback)
executor.runAllReady()
// Then remove it at time HOLD - 1
- doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOps(anyBoolean())
+ doReturn(emptyList<PrivacyItem>()).`when`(privacyItemMonitor).getActivePrivacyItems()
fakeClock.advanceTime(PrivacyItemController.TIME_TO_HOLD_INDICATORS - 1)
- verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
- argCaptorCallback.value.onActiveStateChanged(
- AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, false)
+ verify(privacyItemMonitor).startListening(capture(argCaptorCallback))
+ argCaptorCallback.value.onPrivacyItemsChanged()
executor.runAllReady()
// See it's still there
@@ -503,18 +333,18 @@ class PrivacyItemControllerTest : SysuiTestCase() {
fun testElementAutoRemovedAfterHoldTime() {
// Start with some element at time 0
doReturn(listOf(
- AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, elapsedTime)
- )).`when`(appOpsController).getActiveAppOps(anyBoolean())
+ PrivacyItem(PrivacyType.TYPE_CAMERA,
+ PrivacyApplication(TEST_PACKAGE_NAME, TEST_UID), 0)
+ )).`when`(privacyItemMonitor).getActivePrivacyItems()
privacyItemController.addCallback(callback)
executor.runAllReady()
// Then remove it at time HOLD - 1
- doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOps(anyBoolean())
+ doReturn(emptyList<PrivacyItem>()).`when`(privacyItemMonitor).getActivePrivacyItems()
fakeClock.advanceTime(PrivacyItemController.TIME_TO_HOLD_INDICATORS - 1)
- verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
- argCaptorCallback.value.onActiveStateChanged(
- AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, false)
+ verify(privacyItemMonitor).startListening(capture(argCaptorCallback))
+ argCaptorCallback.value.onPrivacyItemsChanged()
executor.runAllReady()
fakeClock.advanceTime(2L)
@@ -526,38 +356,65 @@ class PrivacyItemControllerTest : SysuiTestCase() {
}
@Test
- fun testPausedElementsAreRemoved() {
- val item = AppOpItem(
- AppOpsManager.OP_RECORD_AUDIO,
- TEST_UID,
- TEST_PACKAGE_NAME,
- elapsedTime
- )
- `when`(appOpsController.getActiveAppOps(anyBoolean())).thenReturn(listOf(item))
+ fun testFlagsAll_listeningToAll() {
+ verify(privacyConfig).addCallback(capture(argCaptorConfigCallback))
privacyItemController.addCallback(callback)
+ `when`(privacyConfig.micCameraAvailable).thenReturn(true)
+ `when`(privacyConfig.locationAvailable).thenReturn(true)
+ `when`(privacyConfig.mediaProjectionAvailable).thenReturn(true)
+ argCaptorConfigCallback.value.onFlagMicCameraChanged(true)
+ argCaptorConfigCallback.value.onFlagLocationChanged(true)
+ argCaptorConfigCallback.value.onFlagMediaProjectionChanged(true)
executor.runAllReady()
- item.isDisabled = true
- fakeClock.advanceTime(1)
- verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
- argCaptorCallback.value.onActiveStateChanged(
- AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, false)
+ assertTrue(privacyItemController.allIndicatorsAvailable)
+ }
+ @Test
+ fun testFlags_onFlagMicCameraChanged() {
+ verify(privacyConfig).addCallback(capture(argCaptorConfigCallback))
+ privacyItemController.addCallback(callback)
+ `when`(privacyConfig.micCameraAvailable).thenReturn(true)
+ argCaptorConfigCallback.value.onFlagMicCameraChanged(true)
executor.runAllReady()
- verify(callback).onPrivacyItemsChanged(emptyList())
- assertTrue(privacyItemController.privacyList.isEmpty())
+ assertTrue(privacyItemController.micCameraAvailable)
+ verify(callback).onFlagMicCameraChanged(true)
+ }
+
+ @Test
+ fun testFlags_onFlagLocationChanged() {
+ verify(privacyConfig).addCallback(capture(argCaptorConfigCallback))
+ privacyItemController.addCallback(callback)
+ `when`(privacyConfig.locationAvailable).thenReturn(true)
+ argCaptorConfigCallback.value.onFlagLocationChanged(true)
+ executor.runAllReady()
+
+ assertTrue(privacyItemController.locationAvailable)
+ verify(callback).onFlagLocationChanged(true)
}
- private fun changeMicCamera(value: Boolean?) = changeProperty(MIC_CAMERA, value)
- private fun changeLocation(value: Boolean?) = changeProperty(LOCATION_INDICATOR, value)
+ @Test
+ fun testFlags_onFlagMediaProjectionChanged() {
+ verify(privacyConfig).addCallback(capture(argCaptorConfigCallback))
+ privacyItemController.addCallback(callback)
+ `when`(privacyConfig.mediaProjectionAvailable).thenReturn(true)
+ argCaptorConfigCallback.value.onFlagMediaProjectionChanged(true)
+ executor.runAllReady()
- private fun changeProperty(name: String, value: Boolean?) {
- deviceConfigProxy.setProperty(
- DeviceConfig.NAMESPACE_PRIVACY,
- name,
- value?.toString(),
- false
- )
+ verify(callback).onFlagMediaProjectionChanged(true)
+ }
+
+ @Test
+ fun testPausedElementsAreRemoved() {
+ doReturn(listOf(
+ PrivacyItem(PrivacyType.TYPE_MICROPHONE,
+ PrivacyApplication(TEST_PACKAGE_NAME, TEST_UID), 0, true)))
+ .`when`(privacyItemMonitor).getActivePrivacyItems()
+
+ privacyItemController.addCallback(callback)
+ executor.runAllReady()
+
+ assertTrue(privacyItemController.privacyList.isEmpty())
}
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index bc1abe62c7ff..be631afdd1a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar
+import android.animation.ObjectAnimator
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
@@ -46,6 +47,7 @@ import org.mockito.Mockito.`when` as whenever
class StatusBarStateControllerImplTest : SysuiTestCase() {
@Mock lateinit var interactionJankMonitor: InteractionJankMonitor
+ @Mock private lateinit var mockDarkAnimator: ObjectAnimator
private lateinit var controller: StatusBarStateControllerImpl
private lateinit var uiEventLogger: UiEventLoggerFake
@@ -57,11 +59,13 @@ class StatusBarStateControllerImplTest : SysuiTestCase() {
whenever(interactionJankMonitor.end(anyInt())).thenReturn(true)
uiEventLogger = UiEventLoggerFake()
- controller = StatusBarStateControllerImpl(
+ controller = object : StatusBarStateControllerImpl(
uiEventLogger,
mock(DumpManager::class.java),
interactionJankMonitor
- )
+ ) {
+ override fun createDarkAnimator(): ObjectAnimator { return mockDarkAnimator }
+ }
}
@Test
@@ -127,4 +131,23 @@ class StatusBarStateControllerImplTest : SysuiTestCase() {
// Double check that we can still force it to happen.
assertTrue(controller.setState(StatusBarState.SHADE, true /* force */))
}
+
+ @Test
+ fun testSetDozeAmount_immediatelyChangesDozeAmount_lockscreenTransitionFromAod() {
+ // Put controller in AOD state
+ controller.setDozeAmount(1f, false)
+
+ // When waking from doze, CentralSurfaces#updateDozingState will update the dozing state
+ // before the doze amount changes
+ controller.setIsDozing(false)
+
+ // Animate the doze amount to 0f, as would normally happen
+ controller.setAndInstrumentDozeAmount(null, 0f, true)
+
+ // Check that the doze amount is immediately set to a value slightly less than 1f. This is
+ // to ensure that any scrim implementation changes its opacity immediately rather than
+ // waiting an extra frame. Waiting an extra frame will cause a relayout (which is expensive)
+ // and cause us to drop a frame during the LOCKSCREEN_TRANSITION_FROM_AOD CUJ.
+ assertEquals(0.99f, controller.dozeAmount, 0.009f)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
index 699f77f9b7bb..2ee31265ff7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
@@ -59,6 +59,7 @@ import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import java.util.ArrayList
+import java.util.function.Consumer
import org.mockito.Mockito.`when` as whenever
@SmallTest
@@ -75,6 +76,7 @@ class HeadsUpCoordinatorTest : SysuiTestCase() {
private lateinit var mBeforeFinalizeFilterListener: OnBeforeFinalizeFilterListener
private lateinit var mOnHeadsUpChangedListener: OnHeadsUpChangedListener
private lateinit var mNotifSectioner: NotifSectioner
+ private lateinit var mActionPressListener: Consumer<NotificationEntry>
private val mNotifPipeline: NotifPipeline = mock()
private val mLogger = HeadsUpCoordinatorLogger(logcatLogBuffer(), verbose = true)
@@ -131,6 +133,9 @@ class HeadsUpCoordinatorTest : SysuiTestCase() {
mOnHeadsUpChangedListener = withArgCaptor {
verify(mHeadsUpManager).addListener(capture())
}
+ mActionPressListener = withArgCaptor {
+ verify(mRemoteInputManager).addActionPressListener(capture())
+ }
given(mHeadsUpManager.allEntries).willAnswer { mHuns.stream() }
given(mHeadsUpManager.isAlerting(anyString())).willAnswer { invocation ->
val key = invocation.getArgument<String>(0)
@@ -199,6 +204,19 @@ class HeadsUpCoordinatorTest : SysuiTestCase() {
}
@Test
+ fun hunExtensionCancelledWhenHunActionPressed() {
+ whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(true)
+ addHUN(mEntry)
+ whenever(mHeadsUpManager.canRemoveImmediately(anyString())).thenReturn(false)
+ whenever(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L)
+ assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
+ mActionPressListener.accept(mEntry)
+ mExecutor.advanceClockToLast()
+ mExecutor.runAllReady()
+ verify(mHeadsUpManager, times(1)).removeNotification(eq(mEntry.key), eq(true))
+ }
+
+ @Test
fun testCancelUpdatedStickyNotification() {
whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(true)
addHUN(mEntry)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index 8a2dc263cf36..7b40ba87b494 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.interruption;
import static android.app.Notification.FLAG_BUBBLE;
+import static android.app.Notification.GROUP_ALERT_SUMMARY;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
@@ -431,6 +432,17 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
}
/**
+ * Test that notification can bubble even if it is a child in a group and group settings are
+ * set to alert only for summary notifications.
+ */
+ @Test
+ public void testShouldBubbleUp_notifInGroupWithOnlySummaryAlerts() {
+ ensureStateForBubbleUp();
+ NotificationEntry bubble = createBubble("testgroup", GROUP_ALERT_SUMMARY);
+ assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(bubble)).isTrue();
+ }
+
+ /**
* If the notification doesn't have permission to bubble, it shouldn't bubble.
*/
@Test
@@ -497,16 +509,27 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
}
private NotificationEntry createBubble() {
+ return createBubble(null, null);
+ }
+
+ private NotificationEntry createBubble(String groupKey, Integer groupAlert) {
Notification.BubbleMetadata data = new Notification.BubbleMetadata.Builder(
PendingIntent.getActivity(mContext, 0, new Intent(),
PendingIntent.FLAG_MUTABLE),
Icon.createWithResource(mContext.getResources(), R.drawable.android))
.build();
- Notification n = new Notification.Builder(getContext(), "a")
+ Notification.Builder nb = new Notification.Builder(getContext(), "a")
.setContentTitle("title")
.setContentText("content text")
- .setBubbleMetadata(data)
- .build();
+ .setBubbleMetadata(data);
+ if (groupKey != null) {
+ nb.setGroup(groupKey);
+ nb.setGroupSummary(false);
+ }
+ if (groupAlert != null) {
+ nb.setGroupAlertBehavior(groupAlert);
+ }
+ Notification n = nb.build();
n.flags |= FLAG_BUBBLE;
return new NotificationEntryBuilder()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
index 663490ebfde0..ef680210e3fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
@@ -125,8 +125,7 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() {
// Each row in separate section.
setGapHeight(gapHeight)
val spaceUsed =
- listOf(
- dividerHeight + rowHeight,
+ listOf(rowHeight,
dividerHeight + gapHeight + rowHeight,
dividerHeight + gapHeight + shelfHeight)
.sum()
@@ -149,9 +148,8 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() {
val rowHeight = rowHeight
val shelfHeight = shelfHeight
val spaceUsed =
- listOf(
- dividerHeight + rowHeight,
- dividerHeight + shelfHeight)
+ listOf(rowHeight,
+ dividerHeight + shelfHeight)
.sum()
val availableSpace = spaceUsed + 1
val rows = listOf(createMockRow(rowHeight), createMockRow(rowHeight))
@@ -195,7 +193,7 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() {
val space = sizeCalculator.spaceNeeded(expandableView, visibleIndex = 0,
previousView = null, stack = stackLayout, onLockscreen = true)
- assertThat(space).isEqualTo(5 + dividerHeight)
+ assertThat(space).isEqualTo(5)
}
@Test
@@ -209,7 +207,7 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() {
val space = sizeCalculator.spaceNeeded(expandableView, visibleIndex = 0,
previousView = null, stack = stackLayout, onLockscreen = false)
- assertThat(space).isEqualTo(10 + dividerHeight)
+ assertThat(space).isEqualTo(10)
}
private fun computeMaxKeyguardNotifications(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index aa54711096ea..5d898b65b60c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -124,6 +124,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true);
when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
+ when(mKeyguardStateController.isUnlocked()).thenReturn(false);
when(mKeyguardBypassController.onBiometricAuthenticated(any(), anyBoolean()))
.thenReturn(true);
when(mAuthController.isUdfpsFingerDown()).thenReturn(false);
@@ -185,6 +186,24 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
}
@Test
+ public void onBiometricAuthenticated_whenDeviceIsAlreadyUnlocked_wakeAndUnlock() {
+ reset(mUpdateMonitor);
+ reset(mStatusBarKeyguardViewManager);
+ when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false);
+ when(mKeyguardStateController.isUnlocked()).thenReturn(true);
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
+ when(mDozeScrimController.isPulsing()).thenReturn(false);
+ // the value of isStrongBiometric doesn't matter here since we only care about the returned
+ // value of isUnlockingWithBiometricAllowed()
+ mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
+ BiometricSourceType.FINGERPRINT, true /* isStrongBiometric */);
+
+ verify(mKeyguardViewMediator).onWakeAndUnlocking();
+ assertThat(mBiometricUnlockController.getMode())
+ .isEqualTo(BiometricUnlockController.MODE_WAKE_AND_UNLOCK);
+ }
+
+ @Test
public void onBiometricAuthenticated_whenFingerprint_notifyKeyguardAuthenticated() {
when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
// the value of isStrongBiometric doesn't matter here since we only care about the returned
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index d364505445f0..16f934b5af59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -477,7 +477,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
mJankMonitor,
mDeviceStateManager,
mDreamOverlayStateController,
- mWiredChargingRippleController);
+ mWiredChargingRippleController, mDreamManager);
when(mKeyguardViewMediator.registerCentralSurfaces(
any(CentralSurfacesImpl.class),
any(NotificationPanelViewController.class),
@@ -534,6 +534,36 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
}
@Test
+ public void executeRunnableDismissingKeyguard_dreaming_notShowing() throws RemoteException {
+ when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false);
+ when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false);
+ when(mKeyguardUpdateMonitor.isDreaming()).thenReturn(true);
+
+ mCentralSurfaces.executeRunnableDismissingKeyguard(() -> {},
+ /* cancelAction= */ null,
+ /* dismissShade= */ false,
+ /* afterKeyguardGone= */ false,
+ /* deferred= */ false);
+ mUiBgExecutor.runAllReady();
+ verify(mDreamManager, times(1)).awaken();
+ }
+
+ @Test
+ public void executeRunnableDismissingKeyguard_notDreaming_notShowing() throws RemoteException {
+ when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false);
+ when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false);
+ when(mKeyguardUpdateMonitor.isDreaming()).thenReturn(false);
+
+ mCentralSurfaces.executeRunnableDismissingKeyguard(() -> {},
+ /* cancelAction= */ null,
+ /* dismissShade= */ false,
+ /* afterKeyguardGone= */ false,
+ /* deferred= */ false);
+ mUiBgExecutor.runAllReady();
+ verify(mDreamManager, never()).awaken();
+ }
+
+ @Test
public void lockscreenStateMetrics_notShowing() {
// uninteresting state, except that fingerprint must be non-zero
when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
index 84e6df23e740..797f86ae14c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
@@ -44,6 +44,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -122,6 +123,7 @@ public class ToastUITest extends SysuiTestCase {
mContextSpy = spy(mContext);
when(mContextSpy.getPackageManager()).thenReturn(mPackageManager);
doReturn(mContextSpy).when(mContextSpy).createContextAsUser(any(), anyInt());
+ doReturn(mContextSpy).when(mContextSpy).createDisplayContext(any());
mToastUI = new ToastUI(
mContextSpy,
mCommandQueue,
@@ -144,7 +146,7 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testShowToast_addsCorrectViewToWindowManager() {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
- null);
+ null, Display.DEFAULT_DISPLAY);
verify(mWindowManager).addView(mViewCaptor.capture(), any());
View view = mViewCaptor.getValue();
@@ -154,7 +156,7 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testShowToast_addsViewWithCorrectLayoutParamsToWindowManager() {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
- null);
+ null, Display.DEFAULT_DISPLAY);
verify(mWindowManager).addView(any(), mParamsCaptor.capture());
ViewGroup.LayoutParams params = mParamsCaptor.getValue();
@@ -170,7 +172,7 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testShowToast_forAndroidPackage_addsAllUserFlag() throws Exception {
mToastUI.showToast(ANDROID_UID, "android", TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
- null);
+ null, Display.DEFAULT_DISPLAY);
verify(mWindowManager).addView(any(), mParamsCaptor.capture());
ViewGroup.LayoutParams params = mParamsCaptor.getValue();
@@ -183,7 +185,7 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testShowToast_forSystemUiPackage_addsAllUserFlag() throws Exception {
mToastUI.showToast(SYSTEMUI_UID, "com.android.systemui", TOKEN_1, TEXT, WINDOW_TOKEN_1,
- Toast.LENGTH_LONG, null);
+ Toast.LENGTH_LONG, null, Display.DEFAULT_DISPLAY);
verify(mWindowManager).addView(any(), mParamsCaptor.capture());
ViewGroup.LayoutParams params = mParamsCaptor.getValue();
@@ -196,7 +198,7 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testShowToast_callsCallback() throws Exception {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
- mCallback);
+ mCallback, Display.DEFAULT_DISPLAY);
verify(mCallback).onToastShown();
}
@@ -216,7 +218,7 @@ public class ToastUITest extends SysuiTestCase {
mAccessibilityManager).sendAccessibilityEvent(any(), anyInt());
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
- null);
+ null, Display.DEFAULT_DISPLAY);
eventParcel.setDataPosition(0);
assertThat(eventParcel.dataSize()).isGreaterThan(0);
@@ -231,14 +233,14 @@ public class ToastUITest extends SysuiTestCase {
public void testShowToast_accessibilityManagerClientIsRemoved() throws Exception {
when(mContextSpy.getUserId()).thenReturn(USER_ID);
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
- null);
+ null, Display.DEFAULT_DISPLAY);
verify(mAccessibilityManager).removeClient(any(), eq(USER_ID));
}
@Test
public void testHideToast_removesView() throws Exception {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
- mCallback);
+ mCallback, Display.DEFAULT_DISPLAY);
final SystemUIToast toast = mToastUI.mToast;
View view = verifyWmAddViewAndAttachToParent();
@@ -254,7 +256,7 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testHideToast_finishesToken() throws Exception {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
- mCallback);
+ mCallback, Display.DEFAULT_DISPLAY);
final SystemUIToast toast = mToastUI.mToast;
verifyWmAddViewAndAttachToParent();
@@ -270,7 +272,7 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testHideToast_callsCallback() throws RemoteException {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
- mCallback);
+ mCallback, Display.DEFAULT_DISPLAY);
final SystemUIToast toast = mToastUI.mToast;
verifyWmAddViewAndAttachToParent();
@@ -286,7 +288,7 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testHideToast_whenNotCurrentToastToken_doesNotHideToast() throws RemoteException {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
- mCallback);
+ mCallback, Display.DEFAULT_DISPLAY);
final SystemUIToast toast = mToastUI.mToast;
verifyWmAddViewAndAttachToParent();
@@ -302,7 +304,7 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testHideToast_whenNotCurrentToastPackage_doesNotHideToast() throws RemoteException {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
- mCallback);
+ mCallback, Display.DEFAULT_DISPLAY);
final SystemUIToast toast = mToastUI.mToast;
verifyWmAddViewAndAttachToParent();
@@ -318,12 +320,12 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testShowToast_afterShowToast_hidesCurrentToast() throws RemoteException {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
- mCallback);
+ mCallback, Display.DEFAULT_DISPLAY);
final SystemUIToast toast = mToastUI.mToast;
View view = verifyWmAddViewAndAttachToParent();
mToastUI.showToast(UID_2, PACKAGE_NAME_2, TOKEN_2, TEXT, WINDOW_TOKEN_2, Toast.LENGTH_LONG,
- null);
+ null, Display.DEFAULT_DISPLAY);
if (toast.getOutAnimation() != null) {
assertThat(toast.getOutAnimation().isRunning()).isTrue();
@@ -338,7 +340,7 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testShowToast_logs() {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
- mCallback);
+ mCallback, Display.DEFAULT_DISPLAY);
verify(mToastLogger).logOnShowToast(UID_1, PACKAGE_NAME_1, TEXT, TOKEN_1.toString());
}
@@ -354,7 +356,7 @@ public class ToastUITest extends SysuiTestCase {
// WHEN the package posts a toast
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
- mCallback);
+ mCallback, Display.DEFAULT_DISPLAY);
// THEN the view can have unlimited lines
assertThat(((TextView) mToastUI.mToast.getView()
@@ -373,7 +375,7 @@ public class ToastUITest extends SysuiTestCase {
// WHEN the package posts a toast
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
- mCallback);
+ mCallback, Display.DEFAULT_DISPLAY);
// THEN the view is limited to 2 lines
assertThat(((TextView) mToastUI.mToast.getView()
@@ -384,7 +386,7 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testHideToast_logs() {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
- mCallback);
+ mCallback, Display.DEFAULT_DISPLAY);
verifyWmAddViewAndAttachToParent();
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
verify(mToastLogger).logOnHideToast(PACKAGE_NAME_1, TOKEN_1.toString());
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index fc95cdd53f29..15d3fa9a03c4 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -69,6 +69,7 @@ import android.util.SparseBooleanArray;
import android.util.TimeUtils;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
+import android.view.autofill.AutofillManager.AutofillCommitReason;
import android.view.autofill.AutofillManager.SmartSuggestionMode;
import android.view.autofill.AutofillManagerInternal;
import android.view.autofill.AutofillValue;
@@ -1657,11 +1658,12 @@ public final class AutofillManagerService
}
@Override
- public void finishSession(int sessionId, int userId) {
+ public void finishSession(int sessionId, int userId,
+ @AutofillCommitReason int commitReason) {
synchronized (mLock) {
final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
if (service != null) {
- service.finishSessionLocked(sessionId, getCallingUid());
+ service.finishSessionLocked(sessionId, getCallingUid(), commitReason);
} else if (sVerbose) {
Slog.v(TAG, "finishSession(): no service for " + userId);
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index aa5c501cd94e..fe85db286fa8 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -70,6 +70,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
+import android.view.autofill.AutofillManager.AutofillCommitReason;
import android.view.autofill.AutofillManager.SmartSuggestionMode;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
@@ -423,7 +424,7 @@ final class AutofillManagerServiceImpl
}
@GuardedBy("mLock")
- void finishSessionLocked(int sessionId, int uid) {
+ void finishSessionLocked(int sessionId, int uid, @AutofillCommitReason int commitReason) {
if (!isEnabledLocked()) {
return;
}
@@ -438,7 +439,7 @@ final class AutofillManagerServiceImpl
final Session.SaveResult saveResult = session.showSaveLocked();
- session.logContextCommitted(saveResult.getNoSaveUiReason());
+ session.logContextCommitted(saveResult.getNoSaveUiReason(), commitReason);
if (saveResult.isLogSaveShown()) {
session.logSaveUiShown();
diff --git a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
new file mode 100644
index 000000000000..c6e595b1d785
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill;
+
+import static android.service.autofill.FillEventHistory.Event.UI_TYPE_DIALOG;
+import static android.service.autofill.FillEventHistory.Event.UI_TYPE_INLINE;
+import static android.service.autofill.FillEventHistory.Event.UI_TYPE_MENU;
+import static android.service.autofill.FillEventHistory.Event.UiType;
+import static android.view.autofill.AutofillManager.COMMIT_REASON_ACTIVITY_FINISHED;
+import static android.view.autofill.AutofillManager.COMMIT_REASON_VIEW_CHANGED;
+import static android.view.autofill.AutofillManager.COMMIT_REASON_VIEW_CLICKED;
+import static android.view.autofill.AutofillManager.COMMIT_REASON_VIEW_COMMITTED;
+
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__DIALOG;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__MENU;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__ANY_SHOWN;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_ACTIVITY_FINISHED;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_REQUEST_TIMEOUT;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_SESSION_COMMITTED_PREMATURELY;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_UNKNOWN_REASON;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_CHANGED;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUS_CHANGED;
+import static com.android.server.autofill.Helper.sVerbose;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.service.autofill.Dataset;
+import android.util.Slog;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillManager;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+import java.util.Optional;
+
+/** Helper class to track and log Autofill presentation stats. */
+public final class PresentationStatsEventLogger {
+ private static final String TAG = "PresentationStatsEventLogger";
+
+ /**
+ * Reasons why presentation was not shown. These are wrappers around
+ * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.PresentationEventResult}.
+ */
+ @IntDef(prefix = { "NOT_SHOWN_REASON" }, value = {
+ NOT_SHOWN_REASON_ANY_SHOWN,
+ NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED,
+ NOT_SHOWN_REASON_VIEW_CHANGED,
+ NOT_SHOWN_REASON_ACTIVITY_FINISHED,
+ NOT_SHOWN_REASON_REQUEST_TIMEOUT,
+ NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY,
+ NOT_SHOWN_REASON_UNKNOWN
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface NotShownReason {}
+ public static final int NOT_SHOWN_REASON_ANY_SHOWN = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__ANY_SHOWN;
+ public static final int NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUS_CHANGED;
+ public static final int NOT_SHOWN_REASON_VIEW_CHANGED = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_CHANGED;
+ public static final int NOT_SHOWN_REASON_ACTIVITY_FINISHED = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_ACTIVITY_FINISHED;
+ public static final int NOT_SHOWN_REASON_REQUEST_TIMEOUT = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_REQUEST_TIMEOUT;
+ public static final int NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_SESSION_COMMITTED_PREMATURELY;
+ public static final int NOT_SHOWN_REASON_UNKNOWN = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_UNKNOWN_REASON;
+
+ private final int mSessionId;
+ private Optional<PresentationStatsEventInternal> mEventInternal;
+
+ private PresentationStatsEventLogger(int sessionId) {
+ mSessionId = sessionId;
+ mEventInternal = Optional.empty();
+ }
+
+ public static PresentationStatsEventLogger forSessionId(int sessionId) {
+ return new PresentationStatsEventLogger(sessionId);
+ }
+
+ public void startNewEvent() {
+ if (mEventInternal.isPresent()) {
+ Slog.e(TAG, "Failed to start new event because already have active event.");
+ return;
+ }
+ mEventInternal = Optional.of(new PresentationStatsEventInternal());
+ }
+
+ public void maybeSetRequestId(int requestId) {
+ mEventInternal.ifPresent(event -> event.mRequestId = requestId);
+ }
+
+ public void maybeSetNoPresentationEventReason(@NotShownReason int reason) {
+ mEventInternal.ifPresent(event -> {
+ if (event.mCountShown == 0) {
+ event.mNoPresentationReason = reason;
+ }
+ });
+ }
+
+ public void maybeSetAvailableCount(@Nullable List<Dataset> datasetList,
+ AutofillId currentViewId) {
+ mEventInternal.ifPresent(event -> {
+ int availableCount = getDatasetCountForAutofillId(datasetList, currentViewId);
+ event.mAvailableCount = availableCount;
+ event.mIsDatasetAvailable = availableCount > 0;
+ });
+ }
+
+ public void maybeSetCountShown(@Nullable List<Dataset> datasetList,
+ AutofillId currentViewId) {
+ mEventInternal.ifPresent(event -> {
+ int countShown = getDatasetCountForAutofillId(datasetList, currentViewId);
+ event.mCountShown = countShown;
+ if (countShown > 0) {
+ event.mNoPresentationReason = NOT_SHOWN_REASON_ANY_SHOWN;
+ }
+ });
+ }
+
+ private static int getDatasetCountForAutofillId(@Nullable List<Dataset> datasetList,
+ AutofillId currentViewId) {
+ int availableCount = 0;
+ if (datasetList != null) {
+ for (int i = 0; i < datasetList.size(); i++) {
+ Dataset data = datasetList.get(i);
+ if (data != null && data.getFieldIds() != null
+ && data.getFieldIds().contains(currentViewId)) {
+ availableCount += 1;
+ }
+ }
+ }
+ return availableCount;
+ }
+
+ public void maybeSetCountFilteredUserTyping(int countFilteredUserTyping) {
+ mEventInternal.ifPresent(event -> {
+ event.mCountFilteredUserTyping = countFilteredUserTyping;
+ });
+ }
+
+ public void maybeSetCountNotShownImePresentationNotDrawn(
+ int countNotShownImePresentationNotDrawn) {
+ mEventInternal.ifPresent(event -> {
+ event.mCountNotShownImePresentationNotDrawn = countNotShownImePresentationNotDrawn;
+ });
+ }
+
+ public void maybeSetCountNotShownImeUserNotSeen(int countNotShownImeUserNotSeen) {
+ mEventInternal.ifPresent(event -> {
+ event.mCountNotShownImeUserNotSeen = countNotShownImeUserNotSeen;
+ });
+ }
+
+ public void maybeSetDisplayPresentationType(@UiType int uiType) {
+ mEventInternal.ifPresent(event -> {
+ event.mDisplayPresentationType = getDisplayPresentationType(uiType);
+ });
+ }
+
+ public void logAndEndEvent() {
+ if (!mEventInternal.isPresent()) {
+ Slog.wtf(null, "Shouldn't be logging AutofillPresentationEventReported again for same "
+ + "event");
+ return;
+ }
+ PresentationStatsEventInternal event = mEventInternal.get();
+ if (sVerbose) {
+ Slog.v(TAG, "Log AutofillPresentationEventReported:"
+ + " requestId=" + event.mRequestId
+ + " sessionId=" + mSessionId
+ + " mNoPresentationEventReason=" + event.mNoPresentationReason
+ + " mAvailableCount=" + event.mAvailableCount
+ + " mCountShown=" + event.mCountShown
+ + " mCountFilteredUserTyping=" + event.mCountFilteredUserTyping
+ + " mCountNotShownImePresentationNotDrawn="
+ + event.mCountNotShownImePresentationNotDrawn
+ + " mCountNotShownImeUserNotSeen=" + event.mCountNotShownImeUserNotSeen
+ + " mDisplayPresentationType=" + event.mDisplayPresentationType);
+ }
+
+ // TODO(b/234185326): Distinguish empty responses from other no presentation reasons.
+ if (!event.mIsDatasetAvailable) {
+ mEventInternal = Optional.empty();
+ return;
+ }
+ FrameworkStatsLog.write(
+ AUTOFILL_PRESENTATION_EVENT_REPORTED,
+ event.mRequestId,
+ mSessionId,
+ event.mNoPresentationReason,
+ event.mAvailableCount,
+ event.mCountShown,
+ event.mCountFilteredUserTyping,
+ event.mCountNotShownImePresentationNotDrawn,
+ event.mCountNotShownImeUserNotSeen,
+ event.mDisplayPresentationType);
+ mEventInternal = Optional.empty();
+ }
+
+ private final class PresentationStatsEventInternal {
+ int mRequestId;
+ @NotShownReason int mNoPresentationReason = NOT_SHOWN_REASON_UNKNOWN;
+ boolean mIsDatasetAvailable;
+ int mAvailableCount;
+ int mCountShown;
+ int mCountFilteredUserTyping;
+ int mCountNotShownImePresentationNotDrawn;
+ int mCountNotShownImeUserNotSeen;
+ int mDisplayPresentationType = AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE;
+
+ PresentationStatsEventInternal() {}
+ }
+
+ static int getNoPresentationEventReason(
+ @AutofillManager.AutofillCommitReason int commitReason) {
+ switch (commitReason) {
+ case COMMIT_REASON_VIEW_COMMITTED:
+ return NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY;
+ case COMMIT_REASON_ACTIVITY_FINISHED:
+ return NOT_SHOWN_REASON_ACTIVITY_FINISHED;
+ case COMMIT_REASON_VIEW_CHANGED:
+ return NOT_SHOWN_REASON_VIEW_CHANGED;
+ case COMMIT_REASON_VIEW_CLICKED:
+ // TODO(b/234185326): Add separate reason for view clicked.
+ default:
+ return NOT_SHOWN_REASON_UNKNOWN;
+ }
+ }
+
+ private static int getDisplayPresentationType(@UiType int uiType) {
+ switch (uiType) {
+ case UI_TYPE_MENU:
+ return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__MENU;
+ case UI_TYPE_INLINE:
+ return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE;
+ case UI_TYPE_DIALOG:
+ return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__DIALOG;
+ default:
+ return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE;
+ }
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index ca0a7806898c..0fe9f8f90cea 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -32,6 +32,7 @@ import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
import static android.view.autofill.AutofillManager.ACTION_VALUE_CHANGED;
import static android.view.autofill.AutofillManager.ACTION_VIEW_ENTERED;
import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
+import static android.view.autofill.AutofillManager.COMMIT_REASON_UNKNOWN;
import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString;
@@ -42,6 +43,9 @@ import static com.android.server.autofill.Helper.getNumericValue;
import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sVerbose;
import static com.android.server.autofill.Helper.toArray;
+import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_REQUEST_TIMEOUT;
+import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_VIEW_CHANGED;
+import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
@@ -107,6 +111,7 @@ import android.util.TimeUtils;
import android.view.KeyEvent;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
+import android.view.autofill.AutofillManager.AutofillCommitReason;
import android.view.autofill.AutofillManager.SmartSuggestionMode;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
@@ -391,6 +396,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
};
+ @NonNull
+ @GuardedBy("mLock")
+ private PresentationStatsEventLogger mPresentationStatsEventLogger;
+
void onSwitchInputMethodLocked() {
// One caveat is that for the case where the focus is on a field for which regular autofill
// returns null, and augmented autofill is triggered, and then the user switches the input
@@ -924,6 +933,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
Slog.v(TAG, "Requesting structure for request #" + ordinal + " ,requestId=" + requestId
+ ", flags=" + flags);
}
+ mPresentationStatsEventLogger.maybeSetRequestId(requestId);
// If the focus changes very quickly before the first request is returned each focus change
// triggers a new partition and we end up with many duplicate partitions. This is
@@ -1021,6 +1031,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mComponentName = componentName;
mCompatMode = compatMode;
mSessionState = STATE_ACTIVE;
+ mPresentationStatsEventLogger = PresentationStatsEventLogger.forSessionId(sessionId);
synchronized (mLock) {
mSessionFlags = new SessionFlags();
mSessionFlags.mAugmentedAutofillOnly = forAugmentedAutofillOnly;
@@ -1271,6 +1282,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
message.length());
}
}
+
+ // TODO(b/234185326): Add separate reason for failures.
+ mPresentationStatsEventLogger.maybeSetNoPresentationEventReason(
+ NOT_SHOWN_REASON_REQUEST_TIMEOUT);
+ mPresentationStatsEventLogger.logAndEndEvent();
}
notifyUnavailableToClient(AutofillManager.STATE_UNKNOWN_FAILED,
/* autofillableIds= */ null);
@@ -1859,7 +1875,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
*/
public void logContextCommitted() {
mHandler.sendMessage(obtainMessage(Session::handleLogContextCommitted, this,
- Event.NO_SAVE_UI_REASON_NONE));
+ Event.NO_SAVE_UI_REASON_NONE,
+ COMMIT_REASON_UNKNOWN));
}
/**
@@ -1867,13 +1884,16 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
* when necessary.
*
* @param saveDialogNotShowReason The reason why a save dialog was not shown.
+ * @param commitReason The reason why context is committed.
*/
- public void logContextCommitted(@NoSaveReason int saveDialogNotShowReason) {
+ public void logContextCommitted(@NoSaveReason int saveDialogNotShowReason,
+ @AutofillCommitReason int commitReason) {
mHandler.sendMessage(obtainMessage(Session::handleLogContextCommitted, this,
- saveDialogNotShowReason));
+ saveDialogNotShowReason, commitReason));
}
- private void handleLogContextCommitted(@NoSaveReason int saveDialogNotShowReason) {
+ private void handleLogContextCommitted(@NoSaveReason int saveDialogNotShowReason,
+ @AutofillCommitReason int commitReason) {
final FillResponse lastResponse;
synchronized (mLock) {
lastResponse = getLastResponseLocked("logContextCommited(%s)");
@@ -1903,28 +1923,35 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
// Sets field classification scores
if (userData != null && fcStrategy != null) {
- logFieldClassificationScore(fcStrategy, userData, saveDialogNotShowReason);
+ logFieldClassificationScore(fcStrategy, userData, saveDialogNotShowReason,
+ commitReason);
} else {
- logContextCommitted(null, null, saveDialogNotShowReason);
+ logContextCommitted(null, null, saveDialogNotShowReason, commitReason);
}
}
private void logContextCommitted(@Nullable ArrayList<AutofillId> detectedFieldIds,
@Nullable ArrayList<FieldClassification> detectedFieldClassifications,
- @NoSaveReason int saveDialogNotShowReason) {
+ @NoSaveReason int saveDialogNotShowReason,
+ @AutofillCommitReason int commitReason) {
synchronized (mLock) {
logContextCommittedLocked(detectedFieldIds, detectedFieldClassifications,
- saveDialogNotShowReason);
+ saveDialogNotShowReason, commitReason);
}
}
@GuardedBy("mLock")
private void logContextCommittedLocked(@Nullable ArrayList<AutofillId> detectedFieldIds,
@Nullable ArrayList<FieldClassification> detectedFieldClassifications,
- @NoSaveReason int saveDialogNotShowReason) {
+ @NoSaveReason int saveDialogNotShowReason,
+ @AutofillCommitReason int commitReason) {
final FillResponse lastResponse = getLastResponseLocked("logContextCommited(%s)");
if (lastResponse == null) return;
+ mPresentationStatsEventLogger.maybeSetNoPresentationEventReason(
+ PresentationStatsEventLogger.getNoPresentationEventReason(commitReason));
+ mPresentationStatsEventLogger.logAndEndEvent();
+
final int flags = lastResponse.getFlags();
if ((flags & FillResponse.FLAG_TRACK_CONTEXT_COMMITED) == 0) {
if (sVerbose) Slog.v(TAG, "logContextCommittedLocked(): ignored by flags " + flags);
@@ -2102,7 +2129,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
*/
private void logFieldClassificationScore(@NonNull FieldClassificationStrategy fcStrategy,
@NonNull FieldClassificationUserData userData,
- @NoSaveReason int saveDialogNotShowReason) {
+ @NoSaveReason int saveDialogNotShowReason,
+ @AutofillCommitReason int commitReason) {
final String[] userValues = userData.getValues();
final String[] categoryIds = userData.getCategoryIds();
@@ -2148,7 +2176,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
final RemoteCallback callback = new RemoteCallback((result) -> {
if (result == null) {
if (sDebug) Slog.d(TAG, "setFieldClassificationScore(): no results");
- logContextCommitted(null, null, saveDialogNotShowReason);
+ logContextCommitted(null, null, saveDialogNotShowReason, commitReason);
return;
}
final Scores scores = result.getParcelable(EXTRA_SCORES);
@@ -2210,7 +2238,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
logContextCommitted(detectedFieldIds, detectedFieldClassifications,
- saveDialogNotShowReason);
+ saveDialogNotShowReason, commitReason);
});
fcStrategy.calculateScores(callback, currentValues, userValues, categoryIds,
@@ -2891,6 +2919,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (sDebug) {
Slog.d(TAG, "Set the response has expired.");
}
+ mPresentationStatsEventLogger.maybeSetNoPresentationEventReason(
+ NOT_SHOWN_REASON_VIEW_CHANGED);
+ mPresentationStatsEventLogger.logAndEndEvent();
return;
}
@@ -2936,6 +2967,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (!isRequestSupportFillDialog(flags)) {
mSessionFlags.mFillDialogDisabled = true;
}
+ mPresentationStatsEventLogger.startNewEvent();
requestNewFillResponseLocked(viewState, ViewState.STATE_STARTED_SESSION, flags);
break;
case ACTION_VALUE_CHANGED:
@@ -2994,6 +3026,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return;
}
+ mPresentationStatsEventLogger.maybeSetNoPresentationEventReason(
+ NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED);
+ mPresentationStatsEventLogger.logAndEndEvent();
+
if ((flags & FLAG_MANUAL_REQUEST) == 0) {
// Not a manual request
if (mAugmentedAutofillableIds != null && mAugmentedAutofillableIds.contains(
@@ -3020,10 +3056,18 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
}
+ mPresentationStatsEventLogger.startNewEvent();
if (requestNewFillResponseOnViewEnteredIfNecessaryLocked(id, viewState, flags)) {
return;
}
+ if (viewState.getResponse() != null) {
+ FillResponse response = viewState.getResponse();
+ mPresentationStatsEventLogger.maybeSetRequestId(response.getRequestId());
+ mPresentationStatsEventLogger.maybeSetAvailableCount(
+ response.getDatasets(), mCurrentViewId);
+ }
+
if (isSameViewEntered) {
setFillDialogDisabledAndStartInput();
return;
@@ -3042,6 +3086,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
// on the IME side if it arrives before the input view is finished on the IME.
mInlineSessionController.resetInlineFillUiLocked();
mCurrentViewId = null;
+
+ mPresentationStatsEventLogger.maybeSetNoPresentationEventReason(
+ NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED);
+ mPresentationStatsEventLogger.logAndEndEvent();
}
break;
default:
@@ -3215,6 +3263,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
final ViewState currentView = mViewStates.get(mCurrentViewId);
currentView.setState(ViewState.STATE_FILL_DIALOG_SHOWN);
mService.logDatasetShown(id, mClientState, UI_TYPE_DIALOG);
+
+ mPresentationStatsEventLogger.maybeSetCountShown(
+ response.getDatasets(), mCurrentViewId);
+ mPresentationStatsEventLogger.maybeSetDisplayPresentationType(UI_TYPE_DIALOG);
}
// Just show fill dialog once, so disabled after shown.
// Note: Cannot disable before requestShowFillDialog() because the method
@@ -3232,9 +3284,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (requestShowInlineSuggestionsLocked(response, filterText)) {
final ViewState currentView = mViewStates.get(mCurrentViewId);
currentView.setState(ViewState.STATE_INLINE_SHOWN);
- //TODO(b/137800469): Fix it to log showed only when IME asks for inflation,
+ // TODO(b/137800469): Fix it to log showed only when IME asks for inflation,
// rather than here where framework sends back the response.
mService.logDatasetShown(id, mClientState, UI_TYPE_INLINE);
+
+ // TODO(b/234475358): Log more accurate value of number of inline suggestions
+ // shown, inflated, and filtered.
+ mPresentationStatsEventLogger.maybeSetCountShown(
+ response.getDatasets(), mCurrentViewId);
+ mPresentationStatsEventLogger.maybeSetDisplayPresentationType(UI_TYPE_INLINE);
return;
}
}
@@ -3246,6 +3304,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
synchronized (mLock) {
mService.logDatasetShown(id, mClientState, UI_TYPE_MENU);
+
+ mPresentationStatsEventLogger.maybeSetCountShown(
+ response.getDatasets(), mCurrentViewId);
+ mPresentationStatsEventLogger.maybeSetDisplayPresentationType(UI_TYPE_MENU);
}
synchronized (mLock) {
@@ -3794,6 +3856,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mResponses.put(requestId, newResponse);
mClientState = newClientState != null ? newClientState : newResponse.getClientState();
+ mPresentationStatsEventLogger.maybeSetAvailableCount(
+ newResponse.getDatasets(), mCurrentViewId);
+
setViewStatesLocked(newResponse, ViewState.STATE_FILLABLE, false);
updateFillDialogTriggerIdsLocked();
updateTrackedIdsLocked();
diff --git a/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java b/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java
index 5a1a1ae3908d..c2c630e01bee 100644
--- a/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java
@@ -167,8 +167,6 @@ final class DialogFillUi {
final Window window = mDialog.getWindow();
window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.setDimAmount(0.6f);
window.addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS);
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 078a1d97f5b7..677871f6c85f 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -347,9 +347,7 @@ final class SaveUi {
final Window window = mDialog.getWindow();
window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_DIM_BEHIND
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
+ | WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.setDimAmount(0.6f);
window.addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS);
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 1af35af9fc17..ca7fe0c571d1 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -2359,13 +2359,37 @@ public class UserBackupManagerService {
}
} while (headBusy);
+ if (runBackup) {
+ CountDownLatch latch = new CountDownLatch(1);
+ String[] pkg = new String[]{entry.packageName};
+ try {
+ mRunningFullBackupTask = PerformFullTransportBackupTask.newWithCurrentTransport(
+ this,
+ mOperationStorage,
+ /* observer */ null,
+ pkg,
+ /* updateSchedule */ true,
+ scheduledJob,
+ latch,
+ /* backupObserver */ null,
+ /* monitor */ null,
+ /* userInitiated */ false,
+ "BMS.beginFullBackup()",
+ getEligibilityRulesForOperation(OperationType.BACKUP));
+ } catch (IllegalStateException e) {
+ Slog.w(TAG, "Failed to start backup", e);
+ runBackup = false;
+ }
+ }
+
if (!runBackup) {
if (DEBUG_SCHEDULING) {
Slog.i(
TAG,
addUserIdToLogMessage(
mUserId,
- "Nothing pending full backup; rescheduling +" + latency));
+ "Nothing pending full backup or failed to start the "
+ + "operation; rescheduling +" + latency));
}
final long deferTime = latency; // pin for the closure
FullBackupJob.schedule(mUserId, mContext, deferTime, mConstants);
@@ -2374,21 +2398,6 @@ public class UserBackupManagerService {
// Okay, the top thing is ready for backup now. Do it.
mFullBackupQueue.remove(0);
- CountDownLatch latch = new CountDownLatch(1);
- String[] pkg = new String[]{entry.packageName};
- mRunningFullBackupTask = PerformFullTransportBackupTask.newWithCurrentTransport(
- this,
- mOperationStorage,
- /* observer */ null,
- pkg,
- /* updateSchedule */ true,
- scheduledJob,
- latch,
- /* backupObserver */ null,
- /* monitor */ null,
- /* userInitiated */ false,
- "BMS.beginFullBackup()",
- getEligibilityRulesForOperation(OperationType.BACKUP));
// Acquiring wakelock for PerformFullTransportBackupTask before its start.
mWakelock.acquire();
(new Thread(mRunningFullBackupTask)).start();
@@ -2884,7 +2893,6 @@ public class UserBackupManagerService {
public void fullTransportBackup(String[] pkgNames) {
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
"fullTransportBackup");
-
final int callingUserHandle = UserHandle.getCallingUserId();
// TODO: http://b/22388012
if (callingUserHandle != UserHandle.USER_SYSTEM) {
@@ -2936,6 +2944,9 @@ public class UserBackupManagerService {
for (String pkg : pkgNames) {
enqueueFullBackup(pkg, now);
}
+ } catch (IllegalStateException e) {
+ Slog.w(TAG, "Failed to start backup: ", e);
+ return;
} finally {
Binder.restoreCallingIdentity(oldId);
}
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index e74a3b97edd1..eac98f2b2337 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -99,6 +99,9 @@ import java.util.concurrent.atomic.AtomicLong;
* mBackupRunner.getBackupResultBlocking().
*/
public class PerformFullTransportBackupTask extends FullBackupTask implements BackupRestoreTask {
+ /**
+ * @throws IllegalStateException if there's no transport available.
+ */
public static PerformFullTransportBackupTask newWithCurrentTransport(
UserBackupManagerService backupManagerService,
OperationStorage operationStorage,
@@ -115,6 +118,9 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
TransportManager transportManager = backupManagerService.getTransportManager();
TransportConnection transportConnection = transportManager.getCurrentTransportClient(
caller);
+ if (transportConnection == null) {
+ throw new IllegalStateException("No TransportConnection available");
+ }
OnTaskFinishedListener listener =
listenerCaller ->
transportManager.disposeOfTransportClient(transportConnection,
diff --git a/services/companion/java/com/android/server/companion/AssociationStoreImpl.java b/services/companion/java/com/android/server/companion/AssociationStoreImpl.java
index bd2a97df1d7a..229799a8457d 100644
--- a/services/companion/java/com/android/server/companion/AssociationStoreImpl.java
+++ b/services/companion/java/com/android/server/companion/AssociationStoreImpl.java
@@ -29,6 +29,7 @@ import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.CollectionUtils;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -267,6 +268,21 @@ class AssociationStoreImpl implements AssociationStore {
}
}
+ /**
+ * Dumps current companion device association states.
+ */
+ public void dump(@NonNull PrintWriter out) {
+ out.append("Companion Device Associations: ");
+ if (getAssociations().isEmpty()) {
+ out.append("<empty>\n");
+ } else {
+ out.append("\n");
+ for (AssociationInfo a : getAssociations()) {
+ out.append(" ").append(a.toString()).append('\n');
+ }
+ }
+ }
+
private void broadcastChange(@ChangeType int changeType, AssociationInfo association) {
synchronized (mListeners) {
for (OnChangeListener listener : mListeners) {
diff --git a/services/companion/java/com/android/server/companion/CompanionApplicationController.java b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
index 6eb8e2619cb5..64729a2553df 100644
--- a/services/companion/java/com/android/server/companion/CompanionApplicationController.java
+++ b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
@@ -33,6 +33,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.PerUser;
import com.android.internal.util.CollectionUtils;
+import java.io.PrintWriter;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -234,6 +235,28 @@ class CompanionApplicationController {
primaryServiceConnector.postOnDeviceDisappeared(association);
}
+ void dump(@NonNull PrintWriter out) {
+ out.append("Companion Device Application Controller: \n");
+
+ synchronized (mBoundCompanionApplications) {
+ out.append(" Bound Companion Applications: ");
+ if (mBoundCompanionApplications.size() == 0) {
+ out.append("<empty>\n");
+ } else {
+ out.append("\n");
+ mBoundCompanionApplications.dump(out);
+ }
+ }
+
+ out.append(" Companion Applications Scheduled For Rebinding: ");
+ if (mScheduledForRebindingCompanionApplications.size() == 0) {
+ out.append("<empty>\n");
+ } else {
+ out.append("\n");
+ mScheduledForRebindingCompanionApplications.dump(out);
+ }
+ }
+
private void onPrimaryServiceBindingDied(@UserIdInt int userId, @NonNull String packageName) {
if (DEBUG) Log.i(TAG, "onPrimaryServiceBindingDied() u" + userId + "/" + packageName);
@@ -333,5 +356,23 @@ class CompanionApplicationController {
}
}
}
+
+ private void dump(@NonNull PrintWriter out) {
+ for (int i = 0; i < size(); i++) {
+ final int userId = keyAt(i);
+ final Map<String, T> forUser = get(userId);
+ if (forUser.isEmpty()) {
+ out.append(" u").append(String.valueOf(userId)).append(": <empty>\n");
+ }
+
+ for (Map.Entry<String, T> packageValue : forUser.entrySet()) {
+ final String packageName = packageValue.getKey();
+ final T value = packageValue.getValue();
+ out.append(" u").append(String.valueOf(userId)).append("\\")
+ .append(packageName).append(" -> ")
+ .append(value.toString()).append('\n');
+ }
+ }
+ }
}
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 0bfe2825bdd5..3f7cba6a4d09 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -764,14 +764,9 @@ public class CompanionDeviceManagerService extends SystemService {
return;
}
- // TODO(b/218615185): mAssociationStore.dump() instead
- out.append("Companion Device Associations:").append('\n');
- for (AssociationInfo a : mAssociationStore.getAssociations()) {
- out.append(" ").append(a.toString()).append('\n');
- }
-
- // TODO(b/218615185): mDevicePresenceMonitor.dump()
- // TODO(b/218615185): mCompanionAppController.dump()
+ mAssociationStore.dump(out);
+ mDevicePresenceMonitor.dump(out);
+ mCompanionAppController.dump(out);
}
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
index 9bb1fb9ac9f5..a288f7b2993c 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
@@ -119,13 +119,23 @@ class CompanionDeviceServiceConnector extends ServiceConnector.Impl<ICompanionDe
}
}
+ // This method is only called when app is force-closed via settings,
+ // but does not handle crashes. Binder death should be handled in #binderDied()
@Override
public void onBindingDied(@NonNull ComponentName name) {
- // IMPORTANT: call super!
+ // IMPORTANT: call super! this will also invoke binderDied()
super.onBindingDied(name);
if (DEBUG) Log.d(TAG, "onBindingDied() " + mComponentName.toShortString());
+ }
+
+ @Override
+ public void binderDied() {
+ super.binderDied();
+
+ if (DEBUG) Log.d(TAG, "binderDied() " + mComponentName.toShortString());
+ // Handle primary process being killed
if (mListener != null) {
mListener.onBindingDied(mUserId, mComponentName.getPackageName());
}
diff --git a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
index 89ed301eb661..0e4870af9930 100644
--- a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
+++ b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
@@ -33,6 +33,7 @@ import android.util.Log;
import com.android.server.companion.AssociationStore;
+import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Set;
@@ -293,6 +294,54 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange
throw new SecurityException("Caller is neither Shell nor Root");
}
+ /**
+ * Dumps system information about devices that are marked as "present".
+ */
+ public void dump(@NonNull PrintWriter out) {
+ out.append("Companion Device Present: ");
+ if (mConnectedBtDevices.isEmpty()
+ && mNearbyBleDevices.isEmpty()
+ && mReportedSelfManagedDevices.isEmpty()) {
+ out.append("<empty>\n");
+ return;
+ } else {
+ out.append("\n");
+ }
+
+ out.append(" Connected Bluetooth Devices: ");
+ if (mConnectedBtDevices.isEmpty()) {
+ out.append("<empty>\n");
+ } else {
+ out.append("\n");
+ for (int associationId : mConnectedBtDevices) {
+ AssociationInfo a = mAssociationStore.getAssociationById(associationId);
+ out.append(" ").append(a.toShortString()).append('\n');
+ }
+ }
+
+ out.append(" Nearby BLE Devices: ");
+ if (mNearbyBleDevices.isEmpty()) {
+ out.append("<empty>\n");
+ } else {
+ out.append("\n");
+ for (int associationId : mNearbyBleDevices) {
+ AssociationInfo a = mAssociationStore.getAssociationById(associationId);
+ out.append(" ").append(a.toShortString()).append('\n');
+ }
+ }
+
+ out.append(" Self-Reported Devices: ");
+ if (mReportedSelfManagedDevices.isEmpty()) {
+ out.append("<empty>\n");
+ } else {
+ out.append("\n");
+ for (int associationId : mReportedSelfManagedDevices) {
+ AssociationInfo a = mAssociationStore.getAssociationById(associationId);
+ out.append(" ").append(a.toShortString()).append('\n');
+ }
+ }
+ }
+
private class SimulatedDevicePresenceSchedulerHelper extends Handler {
SimulatedDevicePresenceSchedulerHelper() {
super(Looper.getMainLooper());
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index 0b437446826a..43e2b881927c 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -16,6 +16,8 @@
package com.android.server.companion.virtual;
+import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING;
+import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
import static android.content.pm.ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
@@ -24,6 +26,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.app.compat.CompatChanges;
+import android.companion.AssociationRequest;
import android.companion.virtual.VirtualDeviceManager.ActivityListener;
import android.companion.virtual.VirtualDeviceParams;
import android.companion.virtual.VirtualDeviceParams.ActivityPolicy;
@@ -45,7 +48,6 @@ import com.android.internal.app.BlockedAppStreamingActivity;
import java.util.List;
import java.util.Set;
-import java.util.function.Consumer;
/**
@@ -63,6 +65,14 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
void onRunningAppsChanged(ArraySet<Integer> runningUids);
}
+ /**
+ * For communicating when activities are blocked from running on the display by this policy
+ * controller.
+ */
+ public interface ActivityBlockedCallback {
+ /** Called when an activity is blocked.*/
+ void onActivityBlocked(int displayId, ActivityInfo activityInfo);
+ }
private static final ComponentName BLOCKED_APP_STREAMING_COMPONENT =
new ComponentName("android", BlockedAppStreamingActivity.class.getName());
@@ -86,7 +96,8 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
private final Object mGenericWindowPolicyControllerLock = new Object();
@ActivityPolicy
private final int mDefaultActivityPolicy;
- private final Consumer<ActivityInfo> mActivityBlockedCallback;
+ private final ActivityBlockedCallback mActivityBlockedCallback;
+ private int mDisplayId = Display.INVALID_DISPLAY;
@NonNull
@GuardedBy("mGenericWindowPolicyControllerLock")
@@ -95,6 +106,8 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final ArraySet<RunningAppsChangedListener> mRunningAppsChangedListener =
new ArraySet<>();
+ @Nullable
+ private final @AssociationRequest.DeviceProfile String mDeviceProfile;
/**
* Creates a window policy controller that is generic to the different use cases of virtual
@@ -115,10 +128,10 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
* {@link VirtualDeviceParams#ACTIVITY_POLICY_DEFAULT_ALLOWED}
* @param defaultActivityPolicy Whether activities are default allowed to be displayed or
* blocked.
- * @param activityListener Activity listener to listen for activity changes. The display ID
- * is not populated in this callback and is always {@link Display#INVALID_DISPLAY}.
+ * @param activityListener Activity listener to listen for activity changes.
* @param activityBlockedCallback Callback that is called when an activity is blocked from
* launching.
+ * @param deviceProfile The {@link AssociationRequest.DeviceProfile} of this virtual device.
*/
public GenericWindowPolicyController(int windowFlags, int systemWindowFlags,
@NonNull ArraySet<UserHandle> allowedUsers,
@@ -128,7 +141,8 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
@NonNull Set<ComponentName> blockedActivities,
@ActivityPolicy int defaultActivityPolicy,
@NonNull ActivityListener activityListener,
- @NonNull Consumer<ActivityInfo> activityBlockedCallback) {
+ @NonNull ActivityBlockedCallback activityBlockedCallback,
+ @AssociationRequest.DeviceProfile String deviceProfile) {
super();
mAllowedUsers = allowedUsers;
mAllowedCrossTaskNavigations = new ArraySet<>(allowedCrossTaskNavigations);
@@ -139,6 +153,14 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
mActivityBlockedCallback = activityBlockedCallback;
setInterestedWindowFlags(windowFlags, systemWindowFlags);
mActivityListener = activityListener;
+ mDeviceProfile = deviceProfile;
+ }
+
+ /**
+ * Expected to be called once this object is associated with a newly created display.
+ */
+ public void setDisplayId(int displayId) {
+ mDisplayId = displayId;
}
/** Register a listener for running applications changes. */
@@ -162,7 +184,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
for (int i = 0; i < activityCount; i++) {
final ActivityInfo aInfo = activities.get(i);
if (!canContainActivity(aInfo, /* windowFlags= */ 0, /* systemWindowFlags= */ 0)) {
- mActivityBlockedCallback.accept(aInfo);
+ mActivityBlockedCallback.onActivityBlocked(mDisplayId, aInfo);
return false;
}
}
@@ -184,7 +206,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
}
if (!canContainActivity(activityInfo, /* windowFlags= */ 0, /* systemWindowFlags= */ 0)) {
- mActivityBlockedCallback.accept(activityInfo);
+ mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
return false;
}
@@ -194,14 +216,14 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
if (isNewTask && !mBlockedCrossTaskNavigations.isEmpty()
&& mBlockedCrossTaskNavigations.contains(activityComponent)) {
Slog.d(TAG, "Virtual device blocking cross task navigation of " + activityComponent);
- mActivityBlockedCallback.accept(activityInfo);
+ mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
return false;
}
if (isNewTask && !mAllowedCrossTaskNavigations.isEmpty()
&& !mAllowedCrossTaskNavigations.contains(activityComponent)) {
Slog.d(TAG, "Virtual device not allowing cross task navigation of "
+ activityComponent);
- mActivityBlockedCallback.accept(activityInfo);
+ mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
return false;
}
@@ -213,7 +235,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
public boolean keepActivityOnWindowFlagsChanged(ActivityInfo activityInfo, int windowFlags,
int systemWindowFlags) {
if (!canContainActivity(activityInfo, windowFlags, systemWindowFlags)) {
- mActivityBlockedCallback.accept(activityInfo);
+ mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
return false;
}
return true;
@@ -227,7 +249,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
if (mActivityListener != null && topActivity != null) {
// Post callback on the main thread so it doesn't block activity launching
mHandler.post(() ->
- mActivityListener.onTopActivityChanged(Display.INVALID_DISPLAY, topActivity));
+ mActivityListener.onTopActivityChanged(mDisplayId, topActivity));
}
}
@@ -238,7 +260,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
mRunningUids.addAll(runningUids);
if (mActivityListener != null && mRunningUids.isEmpty()) {
// Post callback on the main thread so it doesn't block activity launching
- mHandler.post(() -> mActivityListener.onDisplayEmpty(Display.INVALID_DISPLAY));
+ mHandler.post(() -> mActivityListener.onDisplayEmpty(mDisplayId));
}
}
mHandler.post(() -> {
@@ -248,6 +270,21 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
});
}
+ @Override
+ public boolean canShowTasksInRecents() {
+ if (mDeviceProfile == null) {
+ return true;
+ }
+ // TODO(b/234075973) : Remove this once proper API is ready.
+ switch (mDeviceProfile) {
+ case DEVICE_PROFILE_AUTOMOTIVE_PROJECTION:
+ return false;
+ case DEVICE_PROFILE_APP_STREAMING:
+ default:
+ return true;
+ }
+ }
+
/**
* Returns true if an app with the given UID has an activity running on the virtual display for
* this controller.
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 638b3aeef544..5f337ab9bae3 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -64,7 +64,6 @@ import android.util.SparseArray;
import android.view.Display;
import android.view.WindowManager;
import android.widget.Toast;
-import android.window.DisplayWindowPolicyController;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -110,11 +109,11 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
@GuardedBy("mVirtualDeviceLock")
private boolean mDefaultShowPointerIcon = true;
- private ActivityListener createListenerAdapter(int displayId) {
+ private ActivityListener createListenerAdapter() {
return new ActivityListener() {
@Override
- public void onTopActivityChanged(int unusedDisplayId, ComponentName topActivity) {
+ public void onTopActivityChanged(int displayId, ComponentName topActivity) {
try {
mActivityListener.onTopActivityChanged(displayId, topActivity);
} catch (RemoteException e) {
@@ -123,7 +122,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
}
@Override
- public void onDisplayEmpty(int unusedDisplayId) {
+ public void onDisplayEmpty(int displayId) {
try {
mActivityListener.onDisplayEmpty(displayId);
} catch (RemoteException e) {
@@ -242,6 +241,9 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
private void sendPendingIntent(int displayId, PendingIntent pendingIntent)
throws PendingIntent.CanceledException {
+ final ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(displayId);
+ options.setPendingIntentBackgroundActivityLaunchAllowed(true);
+ options.setPendingIntentBackgroundActivityLaunchAllowedByPermission(true);
pendingIntent.send(
mContext,
/* code= */ 0,
@@ -249,9 +251,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
/* onFinished= */ null,
/* handler= */ null,
/* requiredPermission= */ null,
- ActivityOptions.makeBasic()
- .setLaunchDisplayId(displayId)
- .toBundle());
+ options.toBundle());
}
@Override // Binder call
@@ -529,24 +529,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
mInputController.dump(fout);
}
- DisplayWindowPolicyController onVirtualDisplayCreatedLocked(int displayId) {
+ GenericWindowPolicyController createWindowPolicyController() {
synchronized (mVirtualDeviceLock) {
- if (mVirtualDisplayIds.contains(displayId)) {
- throw new IllegalStateException(
- "Virtual device already have a virtual display with ID " + displayId);
- }
- mVirtualDisplayIds.add(displayId);
- mInputController.setShowPointerIcon(mDefaultShowPointerIcon, displayId);
- mInputController.setPointerAcceleration(1f, displayId);
- mInputController.setDisplayEligibilityForPointerCapture(/* isEligible= */ false,
- displayId);
- mInputController.setLocalIme(displayId);
-
- // Since we're being called in the middle of the display being created, we post a
- // task to grab the wakelock instead of doing it synchronously here, to avoid
- // reentrancy problems.
- mContext.getMainThreadHandler().post(() -> addWakeLockForDisplay(displayId));
-
final GenericWindowPolicyController gwpc =
new GenericWindowPolicyController(FLAG_SECURE,
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
@@ -556,18 +540,36 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
mParams.getAllowedActivities(),
mParams.getBlockedActivities(),
mParams.getDefaultActivityPolicy(),
- createListenerAdapter(displayId),
- activityInfo -> onActivityBlocked(displayId, activityInfo));
+ createListenerAdapter(),
+ this::onActivityBlocked,
+ mAssociationInfo.getDeviceProfile());
gwpc.registerRunningAppsChangedListener(/* listener= */ this);
- mWindowPolicyControllers.put(displayId, gwpc);
return gwpc;
}
}
- void addWakeLockForDisplay(int displayId) {
+ void onVirtualDisplayCreatedLocked(GenericWindowPolicyController gwpc, int displayId) {
synchronized (mVirtualDeviceLock) {
- if (!mVirtualDisplayIds.contains(displayId)
- || mPerDisplayWakelocks.containsKey(displayId)) {
+ if (displayId == Display.INVALID_DISPLAY) {
+ return;
+ }
+ if (mVirtualDisplayIds.contains(displayId)) {
+ throw new IllegalStateException(
+ "Virtual device already has a virtual display with ID " + displayId);
+ }
+ mVirtualDisplayIds.add(displayId);
+
+ gwpc.setDisplayId(displayId);
+ mWindowPolicyControllers.put(displayId, gwpc);
+
+ mInputController.setShowPointerIcon(mDefaultShowPointerIcon, displayId);
+ mInputController.setPointerAcceleration(1f, displayId);
+ mInputController.setDisplayEligibilityForPointerCapture(/* isEligible= */ false,
+ displayId);
+ mInputController.setLocalIme(displayId);
+
+
+ if (mPerDisplayWakelocks.containsKey(displayId)) {
Slog.e(TAG, "Not creating wakelock for displayId " + displayId);
return;
}
@@ -575,8 +577,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
TAG + ":" + displayId, displayId);
- wakeLock.acquire();
mPerDisplayWakelocks.put(displayId, wakeLock);
+ wakeLock.acquire();
}
}
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 6398b2142e37..35e9060b58d4 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -31,6 +31,10 @@ import android.companion.virtual.IVirtualDeviceManager;
import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceParams;
import android.content.Context;
+import android.hardware.display.DisplayManagerInternal;
+import android.hardware.display.IVirtualDisplayCallback;
+import android.hardware.display.VirtualDisplayConfig;
+import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -41,9 +45,9 @@ import android.util.ExceptionUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.widget.Toast;
-import android.window.DisplayWindowPolicyController;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.server.SystemService;
import com.android.server.companion.virtual.VirtualDeviceImpl.PendingTrampoline;
@@ -203,6 +207,7 @@ public class VirtualDeviceManagerService extends SystemService {
}
}
+ @VisibleForTesting
class VirtualDeviceManagerImpl extends IVirtualDeviceManager.Stub implements
VirtualDeviceImpl.PendingTrampolineCallback {
@@ -265,6 +270,50 @@ public class VirtualDeviceManagerService extends SystemService {
}
}
+ @Override // Binder call
+ public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
+ IVirtualDisplayCallback callback, IVirtualDevice virtualDevice, String packageName)
+ throws RemoteException {
+ final int callingUid = getCallingUid();
+ if (!PermissionUtils.validateCallingPackageName(getContext(), packageName)) {
+ throw new SecurityException(
+ "Package name " + packageName + " does not belong to calling uid "
+ + callingUid);
+ }
+ VirtualDeviceImpl virtualDeviceImpl;
+ synchronized (mVirtualDeviceManagerLock) {
+ virtualDeviceImpl = mVirtualDevices.get(virtualDevice.getAssociationId());
+ if (virtualDeviceImpl == null) {
+ throw new SecurityException("Invalid VirtualDevice");
+ }
+ }
+ if (virtualDeviceImpl.getOwnerUid() != callingUid) {
+ throw new SecurityException(
+ "uid " + callingUid
+ + " is not the owner of the supplied VirtualDevice");
+ }
+ GenericWindowPolicyController gwpc;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ gwpc = virtualDeviceImpl.createWindowPolicyController();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ DisplayManagerInternal displayManager = getLocalService(
+ DisplayManagerInternal.class);
+ int displayId = displayManager.createVirtualDisplay(virtualDisplayConfig, callback,
+ virtualDevice, gwpc, packageName);
+
+ final long tokenTwo = Binder.clearCallingIdentity();
+ try {
+ virtualDeviceImpl.onVirtualDisplayCreatedLocked(gwpc, displayId);
+ return displayId;
+ } finally {
+ Binder.restoreCallingIdentity(tokenTwo);
+ }
+ }
+
@Nullable
private AssociationInfo getAssociationInfo(String packageName, int associationId) {
final int callingUserId = getCallingUserHandle().getIdentifier();
@@ -337,14 +386,6 @@ public class VirtualDeviceManagerService extends SystemService {
}
@Override
- public DisplayWindowPolicyController onVirtualDisplayCreated(IVirtualDevice virtualDevice,
- int displayId) {
- synchronized (mVirtualDeviceManagerLock) {
- return ((VirtualDeviceImpl) virtualDevice).onVirtualDisplayCreatedLocked(displayId);
- }
- }
-
- @Override
public void onVirtualDisplayRemoved(IVirtualDevice virtualDevice, int displayId) {
synchronized (mVirtualDeviceManagerLock) {
((VirtualDeviceImpl) virtualDevice).onVirtualDisplayRemovedLocked(displayId);
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 24e5de9aa9a0..5c84a628c00d 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -29,7 +29,12 @@
"file_patterns": ["SensorPrivacyService\\.java"]
},
{
- "name": "BinaryTransparencyServiceTest",
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.BinaryTransparencyServiceTest"
+ }
+ ],
"file_patterns": ["BinaryTransparencyService\\.java"]
}
],
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 7a52af61a196..0807fbaf7cc3 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -2355,9 +2355,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
return;
}
- if (VDBG) {
- log("notifyActiveDataSubIdChanged: activeDataSubId=" + activeDataSubId);
- }
+ log("notifyActiveDataSubIdChanged: activeDataSubId=" + activeDataSubId);
+ mLocalLog.log("notifyActiveDataSubIdChanged: activeDataSubId=" + activeDataSubId);
mActiveDataSubId = activeDataSubId;
synchronized (mRecords) {
diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java
index 6667d1b45027..5d0c732d5f48 100644
--- a/services/core/java/com/android/server/adb/AdbService.java
+++ b/services/core/java/com/android/server/adb/AdbService.java
@@ -56,6 +56,7 @@ import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.testharness.TestHarnessModeService;
import java.io.File;
import java.io.FileDescriptor;
@@ -163,18 +164,8 @@ public class AdbService extends IAdbManager.Stub {
}
}
- private void initAdbState() {
+ private void registerContentObservers() {
try {
- /*
- * Use the normal bootmode persistent prop to maintain state of adb across
- * all boot modes.
- */
- mIsAdbUsbEnabled = containsFunction(
- SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY, ""),
- UsbManager.USB_FUNCTION_ADB);
- mIsAdbWifiEnabled = "1".equals(
- SystemProperties.get(WIFI_PERSISTENT_CONFIG_PROPERTY, "0"));
-
// register observer to listen for settings changes
mObserver = new AdbSettingsObserver();
mContentResolver.registerContentObserver(
@@ -184,7 +175,7 @@ public class AdbService extends IAdbManager.Stub {
Settings.Global.getUriFor(Settings.Global.ADB_WIFI_ENABLED),
false, mObserver);
} catch (Exception e) {
- Slog.e(TAG, "Error in initAdbState", e);
+ Slog.e(TAG, "Error in registerContentObservers", e);
}
}
@@ -248,7 +239,7 @@ public class AdbService extends IAdbManager.Stub {
mContentResolver = context.getContentResolver();
mDebuggingManager = new AdbDebuggingManager(context);
- initAdbState();
+ registerContentObservers();
LocalServices.addService(AdbManagerInternal.class, new AdbManagerInternalImpl());
}
@@ -259,10 +250,23 @@ public class AdbService extends IAdbManager.Stub {
public void systemReady() {
if (DEBUG) Slog.d(TAG, "systemReady");
+ /*
+ * Use the normal bootmode persistent prop to maintain state of adb across
+ * all boot modes.
+ */
+ mIsAdbUsbEnabled = containsFunction(
+ SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY, ""),
+ UsbManager.USB_FUNCTION_ADB);
+ boolean shouldEnableAdbUsb = mIsAdbUsbEnabled
+ || SystemProperties.getBoolean(
+ TestHarnessModeService.TEST_HARNESS_MODE_PROPERTY, false);
+ mIsAdbWifiEnabled = "1".equals(
+ SystemProperties.get(WIFI_PERSISTENT_CONFIG_PROPERTY, "0"));
+
// make sure the ADB_ENABLED setting value matches the current state
try {
Settings.Global.putInt(mContentResolver,
- Settings.Global.ADB_ENABLED, mIsAdbUsbEnabled ? 1 : 0);
+ Settings.Global.ADB_ENABLED, shouldEnableAdbUsb ? 1 : 0);
Settings.Global.putInt(mContentResolver,
Settings.Global.ADB_WIFI_ENABLED, mIsAdbWifiEnabled ? 1 : 0);
} catch (SecurityException e) {
@@ -272,7 +276,7 @@ public class AdbService extends IAdbManager.Stub {
}
/**
- * Callend in response to {@code SystemService.PHASE_BOOT_COMPLETED} from {@code SystemServer}.
+ * Called in response to {@code SystemService.PHASE_BOOT_COMPLETED} from {@code SystemServer}.
*/
public void bootCompleted() {
if (DEBUG) Slog.d(TAG, "boot completed");
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index a09174b4152a..5026f318e441 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -5184,7 +5184,7 @@ public final class ActiveServices {
}
boolean bringDownDisabledPackageServicesLocked(String packageName, Set<String> filterByClasses,
- int userId, boolean evenPersistent, boolean doit) {
+ int userId, boolean evenPersistent, boolean fullStop, boolean doit) {
boolean didSomething = false;
if (mTmpCollectionResults != null) {
@@ -5222,6 +5222,18 @@ public final class ActiveServices {
if (size > 0) {
mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
}
+ if (fullStop && !mTmpCollectionResults.isEmpty()) {
+ // if we're tearing down the app's entire service state, account for possible
+ // races around FGS notifications by explicitly tidying up in a separate
+ // pass post-shutdown
+ final ArrayList<ServiceRecord> allServices =
+ (ArrayList<ServiceRecord>) mTmpCollectionResults.clone();
+ mAm.mHandler.postDelayed(() -> {
+ for (int i = 0; i < allServices.size(); i++) {
+ allServices.get(i).cancelNotification();
+ }
+ }, 250L);
+ }
mTmpCollectionResults.clear();
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 75b020912250..f5347055f104 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -128,6 +128,10 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.MemoryStatUtil.hasMemcg;
import static com.android.server.am.ProcessList.ProcStartHandler;
+import static com.android.server.am.ProcessProfileRecord.HOSTING_COMPONENT_TYPE_BACKUP;
+import static com.android.server.am.ProcessProfileRecord.HOSTING_COMPONENT_TYPE_INSTRUMENTATION;
+import static com.android.server.am.ProcessProfileRecord.HOSTING_COMPONENT_TYPE_PERSISTENT;
+import static com.android.server.am.ProcessProfileRecord.HOSTING_COMPONENT_TYPE_SYSTEM;
import static com.android.server.net.NetworkPolicyManagerInternal.updateBlockedReasonsWithProcState;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
@@ -1549,7 +1553,8 @@ public class ActivityManagerService extends IActivityManager.Stub
@GuardedBy("mProcLock")
private ParcelFileDescriptor[] mLifeMonitorFds;
- static final HostingRecord sNullHostingRecord = new HostingRecord(null);
+ static final HostingRecord sNullHostingRecord =
+ new HostingRecord(HostingRecord.HOSTING_TYPE_EMPTY);
/**
* Used to notify activity lifecycle events.
*/
@@ -1877,6 +1882,7 @@ public class ActivityManagerService extends IActivityManager.Stub
app.setPid(MY_PID);
app.mState.setMaxAdj(ProcessList.SYSTEM_ADJ);
app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
+ app.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_SYSTEM);
addPidLocked(app);
updateLruProcessLocked(app, false, null);
updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
@@ -4169,7 +4175,9 @@ public class ActivityManagerService extends IActivityManager.Stub
mi.getTotalRss(),
ProcessStats.ADD_PSS_EXTERNAL_SLOW,
duration,
- holder.appVersion);
+ holder.appVersion,
+ profile.getCurrentHostingComponentTypes(),
+ profile.getHistoricalHostingComponentTypes());
});
}
}
@@ -4227,7 +4235,9 @@ public class ActivityManagerService extends IActivityManager.Stub
tmpUss[2],
ProcessStats.ADD_PSS_EXTERNAL,
duration,
- holder.appVersion);
+ holder.appVersion,
+ profile.getCurrentHostingComponentTypes(),
+ profile.getHistoricalHostingComponentTypes());
});
}
}
@@ -4351,7 +4361,8 @@ public class ActivityManagerService extends IActivityManager.Stub
// Clean-up disabled services.
mServices.bringDownDisabledPackageServicesLocked(
- packageName, disabledClasses, userId, false /* evenPersistent */, true /* doIt */);
+ packageName, disabledClasses, userId, false /* evenPersistent */,
+ false /* fullStop */, true /* doIt */);
// Clean-up disabled providers.
ArrayList<ContentProviderRecord> providers = new ArrayList<>();
@@ -4426,7 +4437,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
mServices.bringDownDisabledPackageServicesLocked(
- packageName, null, userId, false, true);
+ packageName, null, userId, false, true, true);
if (mBooted) {
mAtmInternal.resumeTopActivities(true);
@@ -4479,7 +4490,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (mServices.bringDownDisabledPackageServicesLocked(
- packageName, null /* filterByClasses */, userId, evenPersistent, doit)) {
+ packageName, null /* filterByClasses */, userId, evenPersistent, true, doit)) {
if (!doit) {
return true;
}
@@ -6418,8 +6429,13 @@ public class ActivityManagerService extends IActivityManager.Stub
.getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
for (ApplicationInfo app : apps) {
if (!"android".equals(app.packageName)) {
- addAppLocked(app, null, false, null /* ABI override */,
+ final ProcessRecord proc = addAppLocked(
+ app, null, false, null /* ABI override */,
ZYGOTE_POLICY_FLAG_BATCH_LAUNCH);
+ if (proc != null) {
+ proc.mProfile.addHostingComponentType(
+ HOSTING_COMPONENT_TYPE_PERSISTENT);
+ }
}
}
} catch (RemoteException ex) {
@@ -11298,7 +11314,9 @@ public class ActivityManagerService extends IActivityManager.Stub
holder.state.getPackage(),
myTotalPss, myTotalUss, myTotalRss, reportType,
endTime-startTime,
- holder.appVersion);
+ holder.appVersion,
+ r.mProfile.getCurrentHostingComponentTypes(),
+ r.mProfile.getHistoricalHostingComponentTypes());
});
}
}
@@ -11941,7 +11959,9 @@ public class ActivityManagerService extends IActivityManager.Stub
holder.state.getName(),
holder.state.getPackage(),
myTotalPss, myTotalUss, myTotalRss, reportType, endTime-startTime,
- holder.appVersion);
+ holder.appVersion,
+ r.mProfile.getCurrentHostingComponentTypes(),
+ r.mProfile.getHistoricalHostingComponentTypes());
});
}
}
@@ -12776,6 +12796,8 @@ public class ActivityManagerService extends IActivityManager.Stub
newBackupUid = proc.isInFullBackup() ? r.appInfo.uid : -1;
mBackupTargets.put(targetUserId, r);
+ proc.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_BACKUP);
+
// Try not to kill the process during backup
updateOomAdjLocked(proc, OomAdjuster.OOM_ADJ_REASON_NONE);
@@ -12818,7 +12840,15 @@ public class ActivityManagerService extends IActivityManager.Stub
}
synchronized (this) {
- mBackupTargets.delete(userId);
+ final int indexOfKey = mBackupTargets.indexOfKey(userId);
+ if (indexOfKey >= 0) {
+ final BackupRecord backupTarget = mBackupTargets.valueAt(indexOfKey);
+ if (backupTarget != null && backupTarget.app != null) {
+ backupTarget.app.mProfile.clearHostingComponentType(
+ HOSTING_COMPONENT_TYPE_BACKUP);
+ }
+ mBackupTargets.removeAt(indexOfKey);
+ }
}
JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
@@ -12896,6 +12926,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final ProcessRecord proc = backupTarget.app;
updateOomAdjLocked(proc, OomAdjuster.OOM_ADJ_REASON_NONE);
proc.setInFullBackup(false);
+ proc.mProfile.clearHostingComponentType(HOSTING_COMPONENT_TYPE_BACKUP);
oldBackupUid = backupTarget != null ? backupTarget.appInfo.uid : -1;
@@ -14624,6 +14655,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks,
disableTestApiChecks, abiOverride, ZYGOTE_POLICY_FLAG_EMPTY);
+ app.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_INSTRUMENTATION);
}
app.setActiveInstrumentation(activeInstr);
@@ -14748,6 +14780,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (!mActiveInstrumentation.contains(activeInstr)) {
mActiveInstrumentation.add(activeInstr);
}
+ app.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_INSTRUMENTATION);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -14877,6 +14910,7 @@ public class ActivityManagerService extends IActivityManager.Stub
instr.removeProcess(app);
app.setActiveInstrumentation(null);
}
+ app.mProfile.clearHostingComponentType(HOSTING_COMPONENT_TYPE_INSTRUMENTATION);
if (app.isSdkSandbox) {
// For sharedUid apps this will kill all sdk sandbox processes, which is not ideal.
@@ -15757,6 +15791,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (app.isPersistent()) {
addAppLocked(app.info, null, false, null /* ABI override */,
ZYGOTE_POLICY_FLAG_BATCH_LAUNCH);
+ app.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_PERSISTENT);
}
}
}
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index ed492bc7344c..08c1de61d7fb 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -836,12 +836,18 @@ class AppErrors {
report.type = ApplicationErrorReport.TYPE_CRASH;
report.crashInfo = crashInfo;
} else if (errState.isNotResponding()) {
+ final ActivityManager.ProcessErrorStateInfo anrReport =
+ errState.getNotRespondingReport();
+ if (anrReport == null) {
+ // The ANR dump is still ongoing, ignore it for now.
+ return null;
+ }
report.type = ApplicationErrorReport.TYPE_ANR;
report.anrInfo = new ApplicationErrorReport.AnrInfo();
- report.anrInfo.activity = errState.getNotRespondingReport().tag;
- report.anrInfo.cause = errState.getNotRespondingReport().shortMsg;
- report.anrInfo.info = errState.getNotRespondingReport().longMsg;
+ report.anrInfo.activity = anrReport.tag;
+ report.anrInfo.cause = anrReport.shortMsg;
+ report.anrInfo.info = anrReport.longMsg;
}
return report;
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index 16a728386bd6..61d85689f295 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -573,7 +573,9 @@ public class AppProfiler {
holder.state.getPackage(),
pss, uss, rss,
statType, pssDuration,
- holder.appVersion);
+ holder.appVersion,
+ profile.getCurrentHostingComponentTypes(),
+ profile.getHistoricalHostingComponentTypes());
});
if (DEBUG_PSS) {
Slog.d(TAG_PSS,
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index 6b2679f93cc6..728792f608ef 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -24,6 +24,7 @@ import static android.os.Process.SYSTEM_UID;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
import static com.android.server.am.ActivityManagerService.TAG_MU;
+import static com.android.server.am.ProcessProfileRecord.HOSTING_COMPONENT_TYPE_PROVIDER;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
@@ -701,6 +702,9 @@ public class ContentProviderHelper {
dst.onProviderPublishStatusLocked(true);
}
dst.mRestartCount = 0;
+ if (hasProviderConnectionLocked(r)) {
+ r.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_PROVIDER);
+ }
}
// update the app's oom adj value and each provider's usage stats
@@ -1375,6 +1379,9 @@ public class ContentProviderHelper {
conn.startAssociationIfNeeded();
conn.initializeCount(stable);
cpr.connections.add(conn);
+ if (cpr.proc != null) {
+ cpr.proc.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_PROVIDER);
+ }
pr.addProviderConnection(conn);
mService.startAssociationLocked(r.uid, r.processName, r.mState.getCurProcState(),
cpr.uid, cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
@@ -1418,6 +1425,16 @@ public class ContentProviderHelper {
return true;
}
+ @GuardedBy("mService")
+ private boolean hasProviderConnectionLocked(ProcessRecord proc) {
+ for (int i = proc.mProviders.numberOfProviders() - 1; i >= 0; i--) {
+ if (!proc.mProviders.getProviderAt(i).connections.isEmpty()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private void handleProviderRemoval(ContentProviderConnection conn, boolean stable,
boolean updateOomAdj) {
synchronized (mService) {
@@ -1429,6 +1446,9 @@ public class ContentProviderHelper {
final ContentProviderRecord cpr = conn.provider;
conn.stopAssociation();
cpr.connections.remove(conn);
+ if (cpr.proc != null && !hasProviderConnectionLocked(cpr.proc)) {
+ cpr.proc.mProfile.clearHostingComponentType(HOSTING_COMPONENT_TYPE_PROVIDER);
+ }
conn.client.mProviders.removeProviderConnection(conn);
if (conn.client.mState.getSetProcState()
< ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
@@ -1737,6 +1757,9 @@ public class ContentProviderHelper {
// In the protocol here, we don't expect the client to correctly
// clean up this connection, we'll just remove it.
cpr.connections.remove(i);
+ if (cpr.proc != null && !hasProviderConnectionLocked(cpr.proc)) {
+ cpr.proc.mProfile.clearHostingComponentType(HOSTING_COMPONENT_TYPE_PROVIDER);
+ }
if (conn.client.mProviders.removeProviderConnection(conn)) {
mService.stopAssociationLocked(capp.uid, capp.processName,
cpr.uid, cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
diff --git a/services/core/java/com/android/server/am/HostingRecord.java b/services/core/java/com/android/server/am/HostingRecord.java
index c41dc32094e5..f88a8ce83d02 100644
--- a/services/core/java/com/android/server/am/HostingRecord.java
+++ b/services/core/java/com/android/server/am/HostingRecord.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.os.ProcessStartTime;
@@ -70,7 +71,7 @@ public final class HostingRecord {
public static final String HOSTING_TYPE_TOP_ACTIVITY = "top-activity";
public static final String HOSTING_TYPE_EMPTY = "";
- private final String mHostingType;
+ private @NonNull final String mHostingType;
private final String mHostingName;
private final int mHostingZygote;
private final String mDefiningPackageName;
@@ -79,49 +80,51 @@ public final class HostingRecord {
private final String mDefiningProcessName;
@Nullable private final String mAction;
- public HostingRecord(String hostingType) {
+ public HostingRecord(@NonNull String hostingType) {
this(hostingType, null /* hostingName */, REGULAR_ZYGOTE, null /* definingPackageName */,
-1 /* mDefiningUid */, false /* isTopApp */, null /* definingProcessName */,
null /* action */);
}
- public HostingRecord(String hostingType, ComponentName hostingName) {
+ public HostingRecord(@NonNull String hostingType, ComponentName hostingName) {
this(hostingType, hostingName, REGULAR_ZYGOTE);
}
- public HostingRecord(String hostingType, ComponentName hostingName, @Nullable String action) {
+ public HostingRecord(@NonNull String hostingType, ComponentName hostingName,
+ @Nullable String action) {
this(hostingType, hostingName.toShortString(), REGULAR_ZYGOTE,
null /* definingPackageName */, -1 /* mDefiningUid */, false /* isTopApp */,
null /* definingProcessName */, action);
}
- public HostingRecord(String hostingType, ComponentName hostingName, String definingPackageName,
- int definingUid, String definingProcessName) {
+ public HostingRecord(@NonNull String hostingType, ComponentName hostingName,
+ String definingPackageName, int definingUid, String definingProcessName) {
this(hostingType, hostingName.toShortString(), REGULAR_ZYGOTE, definingPackageName,
definingUid, false /* isTopApp */, definingProcessName, null /* action */);
}
- public HostingRecord(String hostingType, ComponentName hostingName, boolean isTopApp) {
+ public HostingRecord(@NonNull String hostingType, ComponentName hostingName, boolean isTopApp) {
this(hostingType, hostingName.toShortString(), REGULAR_ZYGOTE,
null /* definingPackageName */, -1 /* mDefiningUid */, isTopApp /* isTopApp */,
null /* definingProcessName */, null /* action */);
}
- public HostingRecord(String hostingType, String hostingName) {
+ public HostingRecord(@NonNull String hostingType, String hostingName) {
this(hostingType, hostingName, REGULAR_ZYGOTE);
}
- private HostingRecord(String hostingType, ComponentName hostingName, int hostingZygote) {
+ private HostingRecord(@NonNull String hostingType, ComponentName hostingName,
+ int hostingZygote) {
this(hostingType, hostingName.toShortString(), hostingZygote);
}
- private HostingRecord(String hostingType, String hostingName, int hostingZygote) {
+ private HostingRecord(@NonNull String hostingType, String hostingName, int hostingZygote) {
this(hostingType, hostingName, hostingZygote, null /* definingPackageName */,
-1 /* mDefiningUid */, false /* isTopApp */, null /* definingProcessName */,
null /* action */);
}
- private HostingRecord(String hostingType, String hostingName, int hostingZygote,
+ private HostingRecord(@NonNull String hostingType, String hostingName, int hostingZygote,
String definingPackageName, int definingUid, boolean isTopApp,
String definingProcessName, @Nullable String action) {
mHostingType = hostingType;
@@ -134,7 +137,7 @@ public final class HostingRecord {
mAction = action;
}
- public String getType() {
+ public @NonNull String getType() {
return mHostingType;
}
@@ -230,7 +233,7 @@ public final class HostingRecord {
* @param hostingType
* @return enum HostingType defined in ProcessStartTime proto
*/
- public static int getHostingTypeIdStatsd(String hostingType) {
+ public static int getHostingTypeIdStatsd(@NonNull String hostingType) {
switch(hostingType) {
case HOSTING_TYPE_ACTIVITY:
return ProcessStartTime.HOSTING_TYPE_ACTIVITY;
diff --git a/services/core/java/com/android/server/am/ProcessProfileRecord.java b/services/core/java/com/android/server/am/ProcessProfileRecord.java
index 50970b5b7fa0..cee34d5568b5 100644
--- a/services/core/java/com/android/server/am/ProcessProfileRecord.java
+++ b/services/core/java/com/android/server/am/ProcessProfileRecord.java
@@ -19,6 +19,7 @@ package com.android.server.am;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.ActivityManager.processStateAmToProto;
+import android.annotation.IntDef;
import android.app.IApplicationThread;
import android.content.pm.ApplicationInfo;
import android.os.Debug;
@@ -35,12 +36,95 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.server.am.ProcessList.ProcStateMemTracker;
import java.io.PrintWriter;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
* Profiling info of the process, such as PSS, cpu, etc.
*/
final class ProcessProfileRecord {
+ // Keep below types in sync with the HostingComponentType in the atoms.proto.
+ /**
+ * The type of the component this process is hosting;
+ * this means not hosting any components (cached).
+ */
+ static final int HOSTING_COMPONENT_TYPE_EMPTY = 0x0;
+
+ /**
+ * The type of the component this process is hosting;
+ * this means it's a system process.
+ */
+ static final int HOSTING_COMPONENT_TYPE_SYSTEM = 0x00000001;
+
+ /**
+ * The type of the component this process is hosting;
+ * this means it's a persistent process.
+ */
+ static final int HOSTING_COMPONENT_TYPE_PERSISTENT = 0x00000002;
+
+ /**
+ * The type of the component this process is hosting;
+ * this means it's hosting a backup/restore agent.
+ */
+ static final int HOSTING_COMPONENT_TYPE_BACKUP = 0x00000004;
+
+ /**
+ * The type of the component this process is hosting;
+ * this means it's hosting an instrumentation.
+ */
+ static final int HOSTING_COMPONENT_TYPE_INSTRUMENTATION = 0x00000008;
+
+ /**
+ * The type of the component this process is hosting;
+ * this means it's hosting an activity.
+ */
+ static final int HOSTING_COMPONENT_TYPE_ACTIVITY = 0x00000010;
+
+ /**
+ * The type of the component this process is hosting;
+ * this means it's hosting a broadcast receiver.
+ */
+ static final int HOSTING_COMPONENT_TYPE_BROADCAST_RECEIVER = 0x00000020;
+
+ /**
+ * The type of the component this process is hosting;
+ * this means it's hosting a content provider.
+ */
+ static final int HOSTING_COMPONENT_TYPE_PROVIDER = 0x00000040;
+
+ /**
+ * The type of the component this process is hosting;
+ * this means it's hosting a started service.
+ */
+ static final int HOSTING_COMPONENT_TYPE_STARTED_SERVICE = 0x00000080;
+
+ /**
+ * The type of the component this process is hosting;
+ * this means it's hosting a foreground service.
+ */
+ static final int HOSTING_COMPONENT_TYPE_FOREGROUND_SERVICE = 0x00000100;
+
+ /**
+ * The type of the component this process is hosting;
+ * this means it's being bound via a service binding.
+ */
+ static final int HOSTING_COMPONENT_TYPE_BOUND_SERVICE = 0x00000200;
+
+ @IntDef(flag = true, prefix = { "HOSTING_COMPONENT_TYPE_" }, value = {
+ HOSTING_COMPONENT_TYPE_EMPTY,
+ HOSTING_COMPONENT_TYPE_SYSTEM,
+ HOSTING_COMPONENT_TYPE_PERSISTENT,
+ HOSTING_COMPONENT_TYPE_BACKUP,
+ HOSTING_COMPONENT_TYPE_INSTRUMENTATION,
+ HOSTING_COMPONENT_TYPE_ACTIVITY,
+ HOSTING_COMPONENT_TYPE_BROADCAST_RECEIVER,
+ HOSTING_COMPONENT_TYPE_PROVIDER,
+ HOSTING_COMPONENT_TYPE_STARTED_SERVICE,
+ HOSTING_COMPONENT_TYPE_FOREGROUND_SERVICE,
+ HOSTING_COMPONENT_TYPE_BOUND_SERVICE,
+ })
+ @interface HostingComponentType {}
+
final ProcessRecord mApp;
private final ActivityManagerService mService;
@@ -194,6 +278,12 @@ final class ProcessProfileRecord {
@GuardedBy("mProfilerLock")
private long mLastStateTime;
+ private AtomicInteger mCurrentHostingComponentTypes =
+ new AtomicInteger(HOSTING_COMPONENT_TYPE_EMPTY);
+
+ private AtomicInteger mHistoricalHostingComponentTypes =
+ new AtomicInteger(HOSTING_COMPONENT_TYPE_EMPTY);
+
private final ActivityManagerGlobalLock mProcLock;
ProcessProfileRecord(final ProcessRecord app) {
@@ -292,6 +382,8 @@ final class ProcessProfileRecord {
mThread = null;
}
}
+ mCurrentHostingComponentTypes.set(HOSTING_COMPONENT_TYPE_EMPTY);
+ mHistoricalHostingComponentTypes.set(HOSTING_COMPONENT_TYPE_EMPTY);
}
@GuardedBy("mProfilerLock")
@@ -605,6 +697,23 @@ final class ProcessProfileRecord {
mLastStateTime = state.getLastStateTime();
}
+ void addHostingComponentType(@HostingComponentType int type) {
+ mCurrentHostingComponentTypes.set(mCurrentHostingComponentTypes.get() | type);
+ mHistoricalHostingComponentTypes.set(mHistoricalHostingComponentTypes.get() | type);
+ }
+
+ void clearHostingComponentType(@HostingComponentType int type) {
+ mCurrentHostingComponentTypes.set(mCurrentHostingComponentTypes.get() & ~type);
+ }
+
+ @HostingComponentType int getCurrentHostingComponentTypes() {
+ return mCurrentHostingComponentTypes.get();
+ }
+
+ @HostingComponentType int getHistoricalHostingComponentTypes() {
+ return mHistoricalHostingComponentTypes.get();
+ }
+
@GuardedBy("mService")
void dumpPss(PrintWriter pw, String prefix, long nowUptime) {
synchronized (mProfilerLock) {
@@ -643,6 +752,11 @@ final class ProcessProfileRecord {
pw.print(" reportLowMemory=");
pw.println(mReportLowMemory);
}
+ pw.print(prefix);
+ pw.print("currentHostingComponentTypes=0x");
+ pw.print(Integer.toHexString(getCurrentHostingComponentTypes()));
+ pw.print(" historicalHostingComponentTypes=0x");
+ pw.println(Integer.toHexString(getHistoricalHostingComponentTypes()));
}
void dumpCputime(PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java
index 6b748193c123..486c8ed725e1 100644
--- a/services/core/java/com/android/server/am/ProcessServiceRecord.java
+++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java
@@ -16,6 +16,9 @@
package com.android.server.am;
+import static com.android.server.am.ProcessProfileRecord.HOSTING_COMPONENT_TYPE_BOUND_SERVICE;
+import static com.android.server.am.ProcessProfileRecord.HOSTING_COMPONENT_TYPE_FOREGROUND_SERVICE;
+
import android.app.ActivityManager;
import android.content.Context;
import android.os.IBinder;
@@ -141,6 +144,11 @@ final class ProcessServiceRecord {
mHasForegroundServices = hasForegroundServices;
mFgServiceTypes = fgServiceTypes;
mApp.getWindowProcessController().setHasForegroundServices(hasForegroundServices);
+ if (hasForegroundServices) {
+ mApp.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_FOREGROUND_SERVICE);
+ } else {
+ mApp.mProfile.clearHostingComponentType(HOSTING_COMPONENT_TYPE_FOREGROUND_SERVICE);
+ }
}
boolean hasForegroundServices() {
@@ -295,6 +303,7 @@ final class ProcessServiceRecord {
boolean added = mServices.add(record);
if (added && record.serviceInfo != null) {
mApp.getWindowProcessController().onServiceStarted(record.serviceInfo);
+ updateHostingComonentTypeForBindingsLocked();
}
if (record.lastTopAlmostPerceptibleBindRequestUptimeMs > 0) {
mLastTopStartedAlmostPerceptibleBindRequestUptimeMs = Math.max(
@@ -318,6 +327,9 @@ final class ProcessServiceRecord {
if (record.lastTopAlmostPerceptibleBindRequestUptimeMs > 0) {
updateHasTopStartedAlmostPerceptibleServices();
}
+ if (removed) {
+ updateHostingComonentTypeForBindingsLocked();
+ }
return removed;
}
@@ -437,6 +449,23 @@ final class ProcessServiceRecord {
}
@GuardedBy("mService")
+ void updateHostingComonentTypeForBindingsLocked() {
+ boolean hasBoundClient = false;
+ for (int i = numberOfRunningServices() - 1; i >= 0; i--) {
+ final ServiceRecord sr = getRunningServiceAt(i);
+ if (sr != null && !sr.getConnections().isEmpty()) {
+ hasBoundClient = true;
+ break;
+ }
+ }
+ if (hasBoundClient) {
+ mApp.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_BOUND_SERVICE);
+ } else {
+ mApp.mProfile.clearHostingComponentType(HOSTING_COMPONENT_TYPE_BOUND_SERVICE);
+ }
+ }
+
+ @GuardedBy("mService")
boolean incServiceCrashCountLocked(long now) {
final boolean procIsBoundForeground = mApp.mState.getCurProcState()
== ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index e0660b41a232..262436d693ec 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -21,6 +21,9 @@ import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
+import static com.android.server.am.ProcessProfileRecord.HOSTING_COMPONENT_TYPE_ACTIVITY;
+import static com.android.server.am.ProcessProfileRecord.HOSTING_COMPONENT_TYPE_BROADCAST_RECEIVER;
+import static com.android.server.am.ProcessProfileRecord.HOSTING_COMPONENT_TYPE_STARTED_SERVICE;
import static com.android.server.am.ProcessRecord.TAG;
import android.annotation.ElapsedRealtimeLong;
@@ -694,6 +697,11 @@ final class ProcessStateRecord {
@GuardedBy("mProcLock")
void setHasStartedServices(boolean hasStartedServices) {
mHasStartedServices = hasStartedServices;
+ if (hasStartedServices) {
+ mApp.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_STARTED_SERVICE);
+ } else {
+ mApp.mProfile.clearHostingComponentType(HOSTING_COMPONENT_TYPE_STARTED_SERVICE);
+ }
}
@GuardedBy("mProcLock")
@@ -999,6 +1007,11 @@ final class ProcessStateRecord {
if (mCachedHasActivities == VALUE_INVALID) {
mCachedHasActivities = mApp.getWindowProcessController().hasActivities() ? VALUE_TRUE
: VALUE_FALSE;
+ if (mCachedHasActivities == VALUE_TRUE) {
+ mApp.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_ACTIVITY);
+ } else {
+ mApp.mProfile.clearHostingComponentType(HOSTING_COMPONENT_TYPE_ACTIVITY);
+ }
}
return mCachedHasActivities == VALUE_TRUE;
}
@@ -1065,6 +1078,9 @@ final class ProcessStateRecord {
if (mCachedIsReceivingBroadcast == VALUE_TRUE) {
mCachedSchedGroup = tmpQueue.contains(mService.mFgBroadcastQueue)
? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
+ mApp.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_BROADCAST_RECEIVER);
+ } else {
+ mApp.mProfile.clearHostingComponentType(HOSTING_COMPONENT_TYPE_BROADCAST_RECEIVER);
}
}
return mCachedIsReceivingBroadcast == VALUE_TRUE;
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 480e69bd4f19..4b82ad863c8e 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -23,6 +23,7 @@ import static android.os.PowerExemptionManager.REASON_DENIED;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_SERVICE;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ProcessProfileRecord.HOSTING_COMPONENT_TYPE_BOUND_SERVICE;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -693,6 +694,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
app.removeAllowBackgroundActivityStartsToken(this);
}
app.mServices.updateBoundClientUids();
+ app.mServices.updateHostingComonentTypeForBindingsLocked();
}
app = proc;
if (pendingConnectionGroup > 0 && proc != null) {
@@ -717,6 +719,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
}
if (proc != null) {
proc.mServices.updateBoundClientUids();
+ proc.mServices.updateHostingComonentTypeForBindingsLocked();
}
}
@@ -736,6 +739,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
// if we have a process attached, add bound client uid of this connection to it
if (app != null) {
app.mServices.addBoundClientUid(c.clientUid);
+ app.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_BOUND_SERVICE);
}
}
@@ -744,6 +748,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
// if we have a process attached, tell it to update the state of bound clients
if (app != null) {
app.mServices.updateBoundClientUids();
+ app.mServices.updateHostingComonentTypeForBindingsLocked();
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index f0fe2ddd0395..02648c4da76f 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -9171,7 +9171,7 @@ public class AudioService extends IAudioService.Stub
throw new IllegalArgumentException("Invalid timeOutMs/usagesToMute");
}
Log.i(TAG, "muteAwaitConnection dev:" + device + " timeOutMs:" + timeOutMs
- + " usages:" + usages);
+ + " usages:" + Arrays.toString(usages));
if (mDeviceBroker.isDeviceConnected(device)) {
// not throwing an exception as there could be a race between a connection (server-side,
@@ -9223,7 +9223,7 @@ public class AudioService extends IAudioService.Stub
mutedUsages = mMutedUsagesAwaitingConnection;
mMutingExpectedDevice = null;
mMutedUsagesAwaitingConnection = null;
- mPlaybackMonitor.cancelMuteAwaitConnection();
+ mPlaybackMonitor.cancelMuteAwaitConnection("cancelMuteAwaitConnection dev:" + device);
}
dispatchMuteAwaitConnection(cb -> { try { cb.dispatchOnUnmutedEvent(
AudioManager.MuteAwaitConnectionCallback.EVENT_CANCEL, device, mutedUsages);
@@ -9259,8 +9259,8 @@ public class AudioService extends IAudioService.Stub
}
mMutingExpectedDevice = null;
mMutedUsagesAwaitingConnection = null;
- Log.i(TAG, "muteAwaitConnection device " + device + " connected, unmuting");
- mPlaybackMonitor.cancelMuteAwaitConnection();
+ mPlaybackMonitor.cancelMuteAwaitConnection(
+ "checkMuteAwaitConnection device " + device + " connected, unmuting");
}
dispatchMuteAwaitConnection(cb -> { try { cb.dispatchOnUnmutedEvent(
AudioManager.MuteAwaitConnectionCallback.EVENT_CONNECTION, device, mutedUsages);
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index a4468a3e1eec..b3e7e31d37fc 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -1170,8 +1170,8 @@ public final class PlaybackActivityMonitor
}
}
- void cancelMuteAwaitConnection() {
- sEventLogger.loglogi("cancelMuteAwaitConnection()", TAG);
+ void cancelMuteAwaitConnection(String source) {
+ sEventLogger.loglogi("cancelMuteAwaitConnection() from:" + source, TAG);
synchronized (mPlayerLock) {
// cancel scheduled timeout, ignore device, only one expected device at a time
mEventHandler.removeMessages(MSG_L_TIMEOUT_MUTE_AWAIT_CONNECTION);
@@ -1223,7 +1223,7 @@ public final class PlaybackActivityMonitor
+ " uid:" + apc.getClientUid())).printLog(TAG));
apc.getPlayerProxy().applyVolumeShaper(
MUTE_AWAIT_CONNECTION_VSHAPE,
- PLAY_CREATE_IF_NEEDED);
+ PLAY_SKIP_RAMP);
mMutedPlayersAwaitingConnection.add(apc.getPlayerInterfaceId());
} catch (Exception e) {
Log.e(TAG, "awaiting connection: error muting player "
diff --git a/services/core/java/com/android/server/biometrics/OWNERS b/services/core/java/com/android/server/biometrics/OWNERS
index f05f40353e30..cd281e06f40d 100644
--- a/services/core/java/com/android/server/biometrics/OWNERS
+++ b/services/core/java/com/android/server/biometrics/OWNERS
@@ -1,9 +1,14 @@
set noparent
-kchyn@google.com
-jaggies@google.com
-curtislb@google.com
+graciecheng@google.com
ilyamaty@google.com
-joshmccloskey@google.com
+jaggies@google.com
jbolinger@google.com
-graciecheng@google.com
+jeffpu@google.com
+joshmccloskey@google.com
+
+firewall@google.com
+jasonsfchang@google.com
+lbill@google.com
+mingjuwu@google.com
+
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index a26535fbdce3..0c5b19b0fb2e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -345,8 +345,8 @@ public class FingerprintService extends SystemService {
if (!isKeyguard && !Utils.isSettings(getContext(), opPackageName)
&& sensorProps != null && sensorProps.isAnyUdfpsType()) {
try {
- return authenticateWithPrompt(operationId, sensorProps, userId, receiver,
- opPackageName, ignoreEnrollmentState);
+ return authenticateWithPrompt(operationId, sensorProps, callingUid,
+ callingUserId, receiver, opPackageName, ignoreEnrollmentState);
} catch (PackageManager.NameNotFoundException e) {
Slog.e(TAG, "Invalid package", e);
return -1;
@@ -360,6 +360,7 @@ public class FingerprintService extends SystemService {
private long authenticateWithPrompt(
final long operationId,
@NonNull final FingerprintSensorPropertiesInternal props,
+ final int uId,
final int userId,
final IFingerprintServiceReceiver receiver,
final String opPackageName,
@@ -367,7 +368,7 @@ public class FingerprintService extends SystemService {
final Context context = getUiContext();
final Context promptContext = context.createPackageContextAsUser(
- opPackageName, 0 /* flags */, UserHandle.getUserHandleForUid(userId));
+ opPackageName, 0 /* flags */, UserHandle.getUserHandleForUid(uId));
final Executor executor = context.getMainExecutor();
final BiometricPrompt biometricPrompt = new BiometricPrompt.Builder(promptContext)
diff --git a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
index 94d3d15aec33..f2b4d42c8758 100644
--- a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
+++ b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
@@ -17,7 +17,6 @@
package com.android.server.companion.virtual;
import android.companion.virtual.IVirtualDevice;
-import android.window.DisplayWindowPolicyController;
/**
* Virtual device manager local service interface.
@@ -31,17 +30,6 @@ public abstract class VirtualDeviceManagerInternal {
public abstract boolean isValidVirtualDevice(IVirtualDevice virtualDevice);
/**
- * Notify a virtual display is created.
- *
- * @param virtualDevice The virtual device where the virtual display located.
- * @param displayId The display id of the created virtual display.
- *
- * @return The {@link DisplayWindowPolicyController} of the virtual device.
- */
- public abstract DisplayWindowPolicyController onVirtualDisplayCreated(
- IVirtualDevice virtualDevice, int displayId);
-
- /**
* Notify a virtual display is removed.
*
* @param virtualDevice The virtual device where the virtual display located.
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index b9efdf551646..574a3e7eab7e 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -192,10 +192,13 @@ public class MultipathPolicyTracker {
private final int mSubId;
private long mQuota;
- /** Current multipath budget. Nonzero iff we have budget and a UsageCallback is armed. */
- private long mMultipathBudget;
+ /** Current multipath budget. Nonzero iff we have budget. */
+ // The budget could be accessed by multiple threads, make it volatile to ensure the callers
+ // on a different thread will not see the stale value.
+ private volatile long mMultipathBudget;
private final NetworkTemplate mNetworkTemplate;
private final UsageCallback mUsageCallback;
+ private boolean mUsageCallbackRegistered = false;
private NetworkCapabilities mNetworkCapabilities;
private final NetworkStatsManager mStatsManager;
@@ -234,7 +237,6 @@ public class MultipathPolicyTracker {
@Override
public void onThresholdReached(int networkType, String subscriberId) {
if (DBG) Log.d(TAG, "onThresholdReached for network " + network);
- mMultipathBudget = 0;
updateMultipathBudget();
}
};
@@ -376,9 +378,9 @@ public class MultipathPolicyTracker {
if (DBG) {
Log.d(TAG, "Setting callback for " + budget + " bytes on network " + network);
}
- registerUsageCallback(budget);
+ setMultipathBudget(budget);
} else {
- maybeUnregisterUsageCallback();
+ clearMultipathBudget();
}
}
@@ -403,23 +405,30 @@ public class MultipathPolicyTracker {
return mMultipathBudget > 0;
}
- private void registerUsageCallback(long budget) {
+ // Sets the budget and registers a usage callback for it.
+ private void setMultipathBudget(long budget) {
maybeUnregisterUsageCallback();
+ if (DBG) Log.d(TAG, "Registering callback, budget is " + mMultipathBudget);
mStatsManager.registerUsageCallback(mNetworkTemplate, budget,
(command) -> mHandler.post(command), mUsageCallback);
+ mUsageCallbackRegistered = true;
mMultipathBudget = budget;
}
private void maybeUnregisterUsageCallback() {
- if (haveMultipathBudget()) {
- if (DBG) Log.d(TAG, "Unregistering callback, budget was " + mMultipathBudget);
- mStatsManager.unregisterUsageCallback(mUsageCallback);
- mMultipathBudget = 0;
- }
+ if (!mUsageCallbackRegistered) return;
+ if (DBG) Log.d(TAG, "Unregistering callback, budget was " + mMultipathBudget);
+ mStatsManager.unregisterUsageCallback(mUsageCallback);
+ mUsageCallbackRegistered = false;
}
- void shutdown() {
+ private void clearMultipathBudget() {
maybeUnregisterUsageCallback();
+ mMultipathBudget = 0;
+ }
+
+ void shutdown() {
+ clearMultipathBudget();
}
}
diff --git a/services/core/java/com/android/server/connectivity/PacProxyService.java b/services/core/java/com/android/server/connectivity/PacProxyService.java
index 3a97765246c1..2e90a3d86161 100644
--- a/services/core/java/com/android/server/connectivity/PacProxyService.java
+++ b/services/core/java/com/android/server/connectivity/PacProxyService.java
@@ -44,6 +44,7 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
+import android.webkit.URLUtil;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.TrafficStatsConstants;
@@ -232,8 +233,22 @@ public class PacProxyService extends IPacProxyManager.Stub {
* @throws IOException if the URL is malformed, or the PAC file is too big.
*/
private static String get(Uri pacUri) throws IOException {
- URL url = new URL(pacUri.toString());
- URLConnection urlConnection = url.openConnection(java.net.Proxy.NO_PROXY);
+ if (!URLUtil.isValidUrl(pacUri.toString())) {
+ throw new IOException("Malformed URL:" + pacUri);
+ }
+
+ final URL url = new URL(pacUri.toString());
+ URLConnection urlConnection;
+ try {
+ urlConnection = url.openConnection(java.net.Proxy.NO_PROXY);
+ // Catch the possible exceptions and rethrow as IOException to not to crash the system
+ // for illegal input.
+ } catch (IllegalArgumentException e) {
+ throw new IOException("Incorrect proxy type for " + pacUri);
+ } catch (UnsupportedOperationException e) {
+ throw new IOException("Unsupported URL connection type for " + pacUri);
+ }
+
long contentLength = -1;
try {
contentLength = Long.parseLong(urlConnection.getHeaderField("Content-Length"));
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 254a3226e6de..3551ff91f542 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -88,7 +88,10 @@ import android.net.ipsec.ike.IkeSession;
import android.net.ipsec.ike.IkeSessionCallback;
import android.net.ipsec.ike.IkeSessionParams;
import android.net.ipsec.ike.IkeTunnelConnectionParams;
+import android.net.ipsec.ike.exceptions.IkeNetworkLostException;
+import android.net.ipsec.ike.exceptions.IkeNonProtocolException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
+import android.net.ipsec.ike.exceptions.IkeTimeoutException;
import android.os.Binder;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
@@ -186,6 +189,10 @@ public class Vpn {
// the device idle allowlist during service launch and VPN bootstrap.
private static final long VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS = 60 * 1000;
+ // Length of time (in milliseconds) that an app registered for VpnManager events is placed on
+ // the device idle allowlist each time the a VpnManager event is fired.
+ private static final long VPN_MANAGER_EVENT_ALLOWLIST_DURATION_MS = 30 * 1000;
+
private static final String LOCKDOWN_ALLOWLIST_SETTING_NAME =
Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST;
/**
@@ -714,6 +721,14 @@ public class Vpn {
intent.putExtra(VpnManager.EXTRA_ERROR_CLASS, errorClass);
intent.putExtra(VpnManager.EXTRA_ERROR_CODE, errorCode);
}
+
+ // Allow VpnManager app to temporarily run background services to handle this error.
+ // If an app requires anything beyond this grace period, they MUST either declare
+ // themselves as a foreground service, or schedule a job/workitem.
+ DeviceIdleInternal idleController = mDeps.getDeviceIdleInternal();
+ idleController.addPowerSaveTempWhitelistApp(Process.myUid(), packageName,
+ VPN_MANAGER_EVENT_ALLOWLIST_DURATION_MS, mUserId, false, REASON_VPN,
+ "VpnManager event");
try {
return mUserIdContext.startService(intent) != null;
} catch (RuntimeException e) {
@@ -760,31 +775,36 @@ public class Vpn {
// Also notify the new package if there was a provider change.
final boolean shouldNotifyNewPkg = isVpnApp(packageName) && isPackageChanged;
- if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownAllowlist)) {
- saveAlwaysOnPackage();
- // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
- // ConnectivityServiceTest.
- if (shouldNotifyOldPkg && SdkLevel.isAtLeastT()) {
- // If both of shouldNotifyOldPkg & isPackageChanged are true, which means the
- // always-on of old package is disabled or the old package is replaced with the new
- // package. In this case, VpnProfileState should be disconnected.
- sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED,
- -1 /* errorClass */, -1 /* errorCode*/, oldPackage,
- null /* sessionKey */, isPackageChanged ? makeDisconnectedVpnProfileState()
- : makeVpnProfileStateLocked(),
- null /* underlyingNetwork */, null /* nc */, null /* lp */);
- }
- // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
- // ConnectivityServiceTest.
- if (shouldNotifyNewPkg && SdkLevel.isAtLeastT()) {
- sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED,
- -1 /* errorClass */, -1 /* errorCode*/, packageName,
- getSessionKeyLocked(), makeVpnProfileStateLocked(),
- null /* underlyingNetwork */, null /* nc */, null /* lp */);
- }
+ if (!setAlwaysOnPackageInternal(packageName, lockdown, lockdownAllowlist)) {
+ return false;
+ }
+
+ saveAlwaysOnPackage();
+
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
+ // ConnectivityServiceTest.
+ if (!SdkLevel.isAtLeastT()) {
return true;
}
- return false;
+
+ if (shouldNotifyOldPkg) {
+ // If both of shouldNotifyOldPkg & isPackageChanged are true, that means the
+ // always-on of old package is disabled or the old package is replaced with the new
+ // package. In this case, VpnProfileState should be disconnected.
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED,
+ -1 /* errorClass */, -1 /* errorCode*/, oldPackage,
+ null /* sessionKey */, isPackageChanged ? makeDisconnectedVpnProfileState()
+ : makeVpnProfileStateLocked(),
+ null /* underlyingNetwork */, null /* nc */, null /* lp */);
+ }
+
+ if (shouldNotifyNewPkg) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED,
+ -1 /* errorClass */, -1 /* errorCode*/, packageName,
+ getSessionKeyLocked(), makeVpnProfileStateLocked(),
+ null /* underlyingNetwork */, null /* nc */, null /* lp */);
+ }
+ return true;
}
/**
@@ -2530,6 +2550,21 @@ public class Vpn {
}
}
+ @Nullable
+ protected synchronized NetworkCapabilities getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ NetworkCapabilities nc) {
+ if (nc == null) return null;
+ return mConnectivityManager.getRedactedNetworkCapabilitiesForPackage(
+ nc, mOwnerUID, mPackage);
+ }
+
+ @Nullable
+ protected synchronized LinkProperties getRedactedLinkPropertiesOfUnderlyingNetwork(
+ LinkProperties lp) {
+ if (lp == null) return null;
+ return mConnectivityManager.getRedactedLinkPropertiesForPackage(lp, mOwnerUID, mPackage);
+ }
+
/** This class represents the common interface for all VPN runners. */
@VisibleForTesting
abstract class VpnRunner extends Thread {
@@ -2564,6 +2599,10 @@ public class Vpn {
interface IkeV2VpnRunnerCallback {
void onDefaultNetworkChanged(@NonNull Network network);
+ void onDefaultNetworkCapabilitiesChanged(@NonNull NetworkCapabilities nc);
+
+ void onDefaultNetworkLinkPropertiesChanged(@NonNull LinkProperties lp);
+
void onChildOpened(
@NonNull Network network, @NonNull ChildSessionConfiguration childConfig);
@@ -2620,14 +2659,14 @@ public class Vpn {
@Nullable private IpSecTunnelInterface mTunnelIface;
@Nullable private IkeSession mSession;
@Nullable private Network mActiveNetwork;
+ @Nullable private NetworkCapabilities mUnderlyingNetworkCapabilities;
+ @Nullable private LinkProperties mUnderlyingLinkProperties;
private final String mSessionKey;
IkeV2VpnRunner(@NonNull Ikev2VpnProfile profile) {
super(TAG);
mProfile = profile;
mIpSecManager = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
- // Pass mExecutor into Ikev2VpnNetworkCallback and make sure that IkeV2VpnRunnerCallback
- // will be called by the mExecutor thread.
mNetworkCallback = new VpnIkev2Utils.Ikev2VpnNetworkCallback(TAG, this, mExecutor);
mSessionKey = UUID.randomUUID().toString();
}
@@ -2849,6 +2888,16 @@ public class Vpn {
}
}
+ /** Called when the NetworkCapabilities of underlying network is changed */
+ public void onDefaultNetworkCapabilitiesChanged(@NonNull NetworkCapabilities nc) {
+ mUnderlyingNetworkCapabilities = nc;
+ }
+
+ /** Called when the LinkProperties of underlying network is changed */
+ public void onDefaultNetworkLinkPropertiesChanged(@NonNull LinkProperties lp) {
+ mUnderlyingLinkProperties = lp;
+ }
+
/** Marks the state as FAILED, and disconnects. */
private void markFailedAndDisconnect(Exception exception) {
synchronized (Vpn.this) {
@@ -2879,28 +2928,120 @@ public class Vpn {
return;
}
- if (exception instanceof IkeProtocolException) {
- final IkeProtocolException ikeException = (IkeProtocolException) exception;
-
- switch (ikeException.getErrorType()) {
- case IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_INVALID_KE_PAYLOAD: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_SINGLE_PAIR_REQUIRED: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_FAILED_CP_REQUIRED: // Fallthrough
- case IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE:
- // All the above failures are configuration errors, and are terminal
- markFailedAndDisconnect(exception);
- return;
- // All other cases possibly recoverable.
+ synchronized (Vpn.this) {
+ if (exception instanceof IkeProtocolException) {
+ final IkeProtocolException ikeException = (IkeProtocolException) exception;
+
+ switch (ikeException.getErrorType()) {
+ case IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_INVALID_KE_PAYLOAD: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_SINGLE_PAIR_REQUIRED: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_FAILED_CP_REQUIRED: // Fallthrough
+ case IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE:
+ // All the above failures are configuration errors, and are terminal
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are
+ // decoupled from ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_IKE_ERROR,
+ VpnManager.ERROR_CLASS_NOT_RECOVERABLE,
+ ikeException.getErrorType(),
+ getPackage(), mSessionKey, makeVpnProfileStateLocked(),
+ mActiveNetwork,
+ getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ mUnderlyingNetworkCapabilities),
+ getRedactedLinkPropertiesOfUnderlyingNetwork(
+ mUnderlyingLinkProperties));
+ }
+ markFailedAndDisconnect(exception);
+ return;
+ // All other cases possibly recoverable.
+ default:
+ // All the above failures are configuration errors, and are terminal
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are
+ // decoupled from ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_IKE_ERROR,
+ VpnManager.ERROR_CLASS_RECOVERABLE,
+ ikeException.getErrorType(),
+ getPackage(), mSessionKey, makeVpnProfileStateLocked(),
+ mActiveNetwork,
+ getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ mUnderlyingNetworkCapabilities),
+ getRedactedLinkPropertiesOfUnderlyingNetwork(
+ mUnderlyingLinkProperties));
+ }
+ }
+ } else if (exception instanceof IllegalArgumentException) {
+ // Failed to build IKE/ChildSessionParams; fatal profile configuration error
+ markFailedAndDisconnect(exception);
+ return;
+ } else if (exception instanceof IkeNetworkLostException) {
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are
+ // decoupled from ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR,
+ VpnManager.ERROR_CLASS_RECOVERABLE,
+ VpnManager.ERROR_CODE_NETWORK_LOST,
+ getPackage(), mSessionKey, makeVpnProfileStateLocked(),
+ mActiveNetwork,
+ getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ mUnderlyingNetworkCapabilities),
+ getRedactedLinkPropertiesOfUnderlyingNetwork(
+ mUnderlyingLinkProperties));
+ }
+ } else if (exception instanceof IkeNonProtocolException) {
+ if (exception.getCause() instanceof UnknownHostException) {
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are
+ // decoupled from ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR,
+ VpnManager.ERROR_CLASS_RECOVERABLE,
+ VpnManager.ERROR_CODE_NETWORK_UNKNOWN_HOST,
+ getPackage(), mSessionKey, makeVpnProfileStateLocked(),
+ mActiveNetwork,
+ getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ mUnderlyingNetworkCapabilities),
+ getRedactedLinkPropertiesOfUnderlyingNetwork(
+ mUnderlyingLinkProperties));
+ }
+ } else if (exception.getCause() instanceof IkeTimeoutException) {
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are
+ // decoupled from ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR,
+ VpnManager.ERROR_CLASS_RECOVERABLE,
+ VpnManager.ERROR_CODE_NETWORK_PROTOCOL_TIMEOUT,
+ getPackage(), mSessionKey, makeVpnProfileStateLocked(),
+ mActiveNetwork,
+ getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ mUnderlyingNetworkCapabilities),
+ getRedactedLinkPropertiesOfUnderlyingNetwork(
+ mUnderlyingLinkProperties));
+ }
+ } else if (exception.getCause() instanceof IOException) {
+ // TODO(b/230548427): Remove SDK check once VPN related stuff are
+ // decoupled from ConnectivityServiceTest.
+ if (SdkLevel.isAtLeastT()) {
+ sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR,
+ VpnManager.ERROR_CLASS_RECOVERABLE,
+ VpnManager.ERROR_CODE_NETWORK_IO,
+ getPackage(), mSessionKey, makeVpnProfileStateLocked(),
+ mActiveNetwork,
+ getRedactedNetworkCapabilitiesOfUnderlyingNetwork(
+ mUnderlyingNetworkCapabilities),
+ getRedactedLinkPropertiesOfUnderlyingNetwork(
+ mUnderlyingLinkProperties));
+ }
+ }
+ } else if (exception != null) {
+ Log.wtf(TAG, "onSessionLost: exception = " + exception);
}
- } else if (exception instanceof IllegalArgumentException) {
- // Failed to build IKE/ChildSessionParams; fatal profile configuration error
- markFailedAndDisconnect(exception);
- return;
}
mActiveNetwork = null;
+ mUnderlyingNetworkCapabilities = null;
+ mUnderlyingLinkProperties = null;
// Close all obsolete state, but keep VPN alive incase a usable network comes up.
// (Mirrors VpnService behavior)
@@ -2965,6 +3106,8 @@ public class Vpn {
*/
private void disconnectVpnRunner() {
mActiveNetwork = null;
+ mUnderlyingNetworkCapabilities = null;
+ mUnderlyingLinkProperties = null;
mIsRunning = false;
resetIkeState();
diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
index 6982d6095689..17058282d947 100644
--- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
+++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
@@ -50,7 +50,9 @@ import android.net.InetAddresses;
import android.net.IpPrefix;
import android.net.IpSecAlgorithm;
import android.net.IpSecTransform;
+import android.net.LinkProperties;
import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.RouteInfo;
import android.net.eap.EapSessionConfig;
import android.net.ipsec.ike.ChildSaProposal;
@@ -86,7 +88,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
-import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executor;
/**
* Utility class to build and convert IKEv2/IPsec parameters.
@@ -377,10 +379,10 @@ public class VpnIkev2Utils {
static class Ikev2VpnNetworkCallback extends NetworkCallback {
private final String mTag;
private final Vpn.IkeV2VpnRunnerCallback mCallback;
- private final ExecutorService mExecutor;
+ private final Executor mExecutor;
Ikev2VpnNetworkCallback(String tag, Vpn.IkeV2VpnRunnerCallback callback,
- ExecutorService executor) {
+ Executor executor) {
mTag = tag;
mCallback = callback;
mExecutor = executor;
@@ -393,6 +395,22 @@ public class VpnIkev2Utils {
}
@Override
+ public void onCapabilitiesChanged(@NonNull Network network,
+ @NonNull NetworkCapabilities networkCapabilities) {
+ Log.d(mTag, "NC changed for net " + network + " : " + networkCapabilities);
+ mExecutor.execute(
+ () -> mCallback.onDefaultNetworkCapabilitiesChanged(networkCapabilities));
+ }
+
+ @Override
+ public void onLinkPropertiesChanged(@NonNull Network network,
+ @NonNull LinkProperties linkProperties) {
+ Log.d(mTag, "LP changed for net " + network + " : " + linkProperties);
+ mExecutor.execute(
+ () -> mCallback.onDefaultNetworkLinkPropertiesChanged(linkProperties));
+ }
+
+ @Override
public void onLost(@NonNull Network network) {
Log.d(mTag, "Tearing down; lost network: " + network);
mExecutor.execute(() -> mCallback.onSessionLost(network, null));
diff --git a/services/core/java/com/android/server/display/BrightnessSetting.java b/services/core/java/com/android/server/display/BrightnessSetting.java
index ca7b789da47d..74486113dcf9 100644
--- a/services/core/java/com/android/server/display/BrightnessSetting.java
+++ b/services/core/java/com/android/server/display/BrightnessSetting.java
@@ -102,13 +102,15 @@ public class BrightnessSetting {
return;
}
synchronized (mSyncRoot) {
- if (brightness == mBrightness) {
- return;
+ // If the brightness is the same, we still need to update any listeners as the act of
+ // setting the brightness alone has side effects, like clearing any temporary
+ // brightness. We can skip persisting to disk, however, since it hasn't actually
+ // changed.
+ if (brightness != mBrightness) {
+ mPersistentDataStore.setBrightness(mLogicalDisplay.getPrimaryDisplayDeviceLocked(),
+ brightness);
}
-
mBrightness = brightness;
- mPersistentDataStore.setBrightness(mLogicalDisplay.getPrimaryDisplayDeviceLocked(),
- brightness);
int toSend = Float.floatToIntBits(mBrightness);
Message msg = mHandler.obtainMessage(MSG_BRIGHTNESS_CHANGED, toSend, 0);
mHandler.sendMessage(msg);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e77693650eda..6285ef1fdabd 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1231,7 +1231,7 @@ public final class DisplayManagerService extends SystemService {
private int createVirtualDisplayInternal(VirtualDisplayConfig virtualDisplayConfig,
IVirtualDisplayCallback callback, IMediaProjection projection,
- IVirtualDevice virtualDevice, String packageName) {
+ IVirtualDevice virtualDevice, DisplayWindowPolicyController dwpc, String packageName) {
final int callingUid = Binder.getCallingUid();
if (!validatePackageName(callingUid, packageName)) {
throw new SecurityException("packageName must match the calling uid");
@@ -1351,8 +1351,13 @@ public final class DisplayManagerService extends SystemService {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
- return createVirtualDisplayLocked(callback, projection, virtualDevice, callingUid,
+ final int displayId = createVirtualDisplayLocked(callback, projection, callingUid,
packageName, surface, flags, virtualDisplayConfig);
+ if (displayId != Display.INVALID_DISPLAY && virtualDevice != null && dwpc != null) {
+ mDisplayWindowPolicyControllers.put(displayId,
+ Pair.create(virtualDevice, dwpc));
+ }
+ return displayId;
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -1360,8 +1365,7 @@ public final class DisplayManagerService extends SystemService {
}
private int createVirtualDisplayLocked(IVirtualDisplayCallback callback,
- IMediaProjection projection, IVirtualDevice virtualDevice,
- int callingUid, String packageName, Surface surface,
+ IMediaProjection projection, int callingUid, String packageName, Surface surface,
int flags, VirtualDisplayConfig virtualDisplayConfig) {
if (mVirtualDisplayAdapter == null) {
Slog.w(TAG, "Rejecting request to create private virtual display "
@@ -1389,16 +1393,7 @@ public final class DisplayManagerService extends SystemService {
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
if (display != null) {
- final int displayId = display.getDisplayIdLocked();
- if (virtualDevice != null) {
- final VirtualDeviceManagerInternal vdm =
- getLocalService(VirtualDeviceManagerInternal.class);
- final DisplayWindowPolicyController controller =
- vdm.onVirtualDisplayCreated(virtualDevice, displayId);
- mDisplayWindowPolicyControllers.put(displayId,
- Pair.create(virtualDevice, controller));
- }
- return displayId;
+ return display.getDisplayIdLocked();
}
// Something weird happened and the logical display was not created.
@@ -3066,9 +3061,9 @@ public final class DisplayManagerService extends SystemService {
@Override // Binder call
public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
IVirtualDisplayCallback callback, IMediaProjection projection,
- IVirtualDevice virtualDeviceToken, String packageName) {
+ String packageName) {
return createVirtualDisplayInternal(virtualDisplayConfig, callback, projection,
- virtualDeviceToken, packageName);
+ null, null, packageName);
}
@Override // Binder call
@@ -3354,7 +3349,7 @@ public final class DisplayManagerService extends SystemService {
synchronized (mSyncRoot) {
DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
if (dpc != null) {
- dpc.putScreenBrightnessSetting(brightness);
+ dpc.setBrightness(brightness);
}
mPersistentDataStore.saveIfNeeded();
}
@@ -3534,7 +3529,8 @@ public final class DisplayManagerService extends SystemService {
return !Float.isNaN(refreshRate) && (refreshRate > 0.0f);
}
- private final class LocalService extends DisplayManagerInternal {
+ @VisibleForTesting
+ final class LocalService extends DisplayManagerInternal {
@Override
public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler,
@@ -3550,6 +3546,14 @@ public final class DisplayManagerService extends SystemService {
}
@Override
+ public int createVirtualDisplay(VirtualDisplayConfig config,
+ IVirtualDisplayCallback callback, IVirtualDevice virtualDevice,
+ DisplayWindowPolicyController dwpc, String packageName) {
+ return createVirtualDisplayInternal(config, callback, null, virtualDevice, dwpc,
+ packageName);
+ }
+
+ @Override
public boolean requestPowerState(int groupId, DisplayPowerRequest request,
boolean waitForNegativeProximity) {
synchronized (mSyncRoot) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index d13a9a3ec27e..f39c412eed13 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1345,7 +1345,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
slowChange = true; // slowly adapt to auto-brightness
}
- updateScreenBrightnessSetting = true;
+ updateScreenBrightnessSetting = mCurrentScreenBrightnessSetting != brightnessState;
mAppliedAutoBrightness = true;
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_AUTOMATIC);
} else {
@@ -1415,7 +1415,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// before applying the low power or dim transformations so that the slider
// accurately represents the full possible range, even if they range changes what
// it means in absolute terms.
- putScreenBrightnessSetting(brightnessState, /* updateCurrent */ true);
+ updateScreenBrightnessSetting(brightnessState);
}
// Apply dimming by at least some minimum amount when user activity
@@ -2288,17 +2288,18 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
return clampScreenBrightnessForVr(brightnessFloat);
}
- void putScreenBrightnessSetting(float brightnessValue) {
- putScreenBrightnessSetting(brightnessValue, false);
+ void setBrightness(float brightnessValue) {
+ // Update the setting, which will eventually call back into DPC to have us actually update
+ // the display with the new value.
+ mBrightnessSetting.setBrightness(brightnessValue);
}
- private void putScreenBrightnessSetting(float brightnessValue, boolean updateCurrent) {
- if (!isValidBrightnessValue(brightnessValue)) {
+ private void updateScreenBrightnessSetting(float brightnessValue) {
+ if (!isValidBrightnessValue(brightnessValue)
+ || brightnessValue == mCurrentScreenBrightnessSetting) {
return;
}
- if (updateCurrent) {
- setCurrentScreenBrightness(brightnessValue);
- }
+ setCurrentScreenBrightness(brightnessValue);
mBrightnessSetting.setBrightness(brightnessValue);
}
diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java
index 2eba080e369e..59daee9ea2ff 100644
--- a/services/core/java/com/android/server/display/PersistentDataStore.java
+++ b/services/core/java/com/android/server/display/PersistentDataStore.java
@@ -20,6 +20,7 @@ import android.annotation.Nullable;
import android.graphics.Point;
import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.WifiDisplay;
+import android.os.Handler;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
@@ -31,12 +32,14 @@ import android.util.Xml;
import android.view.Display;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.util.XmlUtils;
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParserException;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
@@ -141,13 +144,22 @@ final class PersistentDataStore {
// The interface for methods which should be replaced by the test harness.
private Injector mInjector;
+ private final Handler mHandler;
+ private final Object mFileAccessLock = new Object();
+
public PersistentDataStore() {
this(new Injector());
}
@VisibleForTesting
PersistentDataStore(Injector injector) {
+ this(injector, BackgroundThread.getHandler());
+ }
+
+ @VisibleForTesting
+ PersistentDataStore(Injector injector, Handler handler) {
mInjector = injector;
+ mHandler = handler;
}
public void saveIfNeeded() {
@@ -418,45 +430,60 @@ final class PersistentDataStore {
}
private void load() {
- clearState();
+ synchronized (mFileAccessLock) {
+ clearState();
- final InputStream is;
- try {
- is = mInjector.openRead();
- } catch (FileNotFoundException ex) {
- return;
- }
+ final InputStream is;
+ try {
+ is = mInjector.openRead();
+ } catch (FileNotFoundException ex) {
+ return;
+ }
- TypedXmlPullParser parser;
- try {
- parser = Xml.resolvePullParser(is);
- loadFromXml(parser);
- } catch (IOException ex) {
- Slog.w(TAG, "Failed to load display manager persistent store data.", ex);
- clearState();
- } catch (XmlPullParserException ex) {
- Slog.w(TAG, "Failed to load display manager persistent store data.", ex);
- clearState();
- } finally {
- IoUtils.closeQuietly(is);
+ TypedXmlPullParser parser;
+ try {
+ parser = Xml.resolvePullParser(is);
+ loadFromXml(parser);
+ } catch (IOException ex) {
+ Slog.w(TAG, "Failed to load display manager persistent store data.", ex);
+ clearState();
+ } catch (XmlPullParserException ex) {
+ Slog.w(TAG, "Failed to load display manager persistent store data.", ex);
+ clearState();
+ } finally {
+ IoUtils.closeQuietly(is);
+ }
}
}
private void save() {
- final OutputStream os;
+ final ByteArrayOutputStream os;
try {
- os = mInjector.startWrite();
- boolean success = false;
- try {
- TypedXmlSerializer serializer = Xml.resolveSerializer(os);
- saveToXml(serializer);
- serializer.flush();
- success = true;
- } finally {
- mInjector.finishWrite(os, success);
- }
+ os = new ByteArrayOutputStream();
+
+ TypedXmlSerializer serializer = Xml.resolveSerializer(os);
+ saveToXml(serializer);
+ serializer.flush();
+
+ mHandler.removeCallbacksAndMessages(/* token */ null);
+ mHandler.post(() -> {
+ synchronized (mFileAccessLock) {
+ OutputStream fileOutput = null;
+ try {
+ fileOutput = mInjector.startWrite();
+ os.writeTo(fileOutput);
+ fileOutput.flush();
+ } catch (IOException ex) {
+ Slog.w(TAG, "Failed to save display manager persistent store data.", ex);
+ } finally {
+ if (fileOutput != null) {
+ mInjector.finishWrite(fileOutput, true);
+ }
+ }
+ }
+ });
} catch (IOException ex) {
- Slog.w(TAG, "Failed to save display manager persistent store data.", ex);
+ Slog.w(TAG, "Failed to process the XML serializer.", ex);
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index 9195b68e7a8f..86969ce1693c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -247,6 +247,7 @@ final class InputMethodBindingController {
private final ServiceConnection mVisibleConnection = new ServiceConnection() {
@Override public void onBindingDied(ComponentName name) {
synchronized (ImfLock.class) {
+ mService.invalidateAutofillSessionLocked();
if (mVisibleBound) {
unbindVisibleConnection();
}
@@ -257,6 +258,9 @@ final class InputMethodBindingController {
}
@Override public void onServiceDisconnected(ComponentName name) {
+ synchronized (ImfLock.class) {
+ mService.invalidateAutofillSessionLocked();
+ }
}
};
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index ea2b1571c0ae..1a1c265f568d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -313,6 +313,15 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@Nullable
private CreateInlineSuggestionsRequest mPendingInlineSuggestionsRequest;
+ /**
+ * A callback into the autofill service obtained from the latest call to
+ * {@link #onCreateInlineSuggestionsRequestLocked}, which can be used to invalidate an
+ * autofill session in case the IME process dies.
+ */
+ @GuardedBy("ImfLock.class")
+ @Nullable
+ private IInlineSuggestionsRequestCallback mInlineSuggestionsRequestCallback;
+
@UserIdInt
private int mLastSwitchUserId;
@@ -2176,6 +2185,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback,
boolean touchExplorationEnabled) {
clearPendingInlineSuggestionsRequestLocked();
+ mInlineSuggestionsRequestCallback = callback;
final InputMethodInfo imi = mMethodMap.get(getSelectedMethodIdLocked());
try {
if (userId == mSettings.getCurrentUserId()
@@ -2797,6 +2807,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
if (DEBUG) {
Slog.d(TAG, "Avoiding IME startup and unbinding current input method.");
}
+ invalidateAutofillSessionLocked();
mBindingController.unbindCurrentMethod();
return InputBindResult.NO_EDITOR;
}
@@ -2835,6 +2846,17 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
@GuardedBy("ImfLock.class")
+ void invalidateAutofillSessionLocked() {
+ if (mInlineSuggestionsRequestCallback != null) {
+ try {
+ mInlineSuggestionsRequestCallback.onInlineSuggestionsSessionInvalidated();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Cannot invalidate autofill session.", e);
+ }
+ }
+ }
+
+ @GuardedBy("ImfLock.class")
private boolean shouldPreventImeStartupLocked(
@NonNull String selectedMethodId,
@StartInputFlags int startInputFlags,
diff --git a/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
index 2e1aaf85d25a..aba7572ee1a0 100644
--- a/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
+++ b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
@@ -599,6 +599,7 @@ class GnssNetworkConnectivityHandler {
SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS);
} catch (RuntimeException e) {
Log.e(TAG, "Failed to request network.", e);
+ mSuplConnectivityCallback = null;
handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
}
}
diff --git a/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java b/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java
index f9a84077817d..98bae3dc247b 100644
--- a/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java
+++ b/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java
@@ -105,7 +105,7 @@ public class LogAccessDialogActivity extends Activity implements
@Override
protected void onDestroy() {
super.onDestroy();
- if (mAlert != null && mAlert.isShowing()) {
+ if (!isChangingConfigurations() && mAlert != null && mAlert.isShowing()) {
mAlert.dismiss();
}
mAlert = null;
diff --git a/services/core/java/com/android/server/notification/toast/TextToastRecord.java b/services/core/java/com/android/server/notification/toast/TextToastRecord.java
index 7b36db2fe38c..559798a34662 100644
--- a/services/core/java/com/android/server/notification/toast/TextToastRecord.java
+++ b/services/core/java/com/android/server/notification/toast/TextToastRecord.java
@@ -62,7 +62,8 @@ public class TextToastRecord extends ToastRecord {
Slog.w(TAG, "StatusBar not available to show text toast for package " + pkg);
return false;
}
- mStatusBar.showToast(uid, pkg, token, text, windowToken, getDuration(), mCallback);
+ mStatusBar.showToast(uid, pkg, token, text, windowToken, getDuration(), mCallback,
+ displayId);
return true;
}
diff --git a/services/core/java/com/android/server/pm/AppsFilterBase.java b/services/core/java/com/android/server/pm/AppsFilterBase.java
index 78e7b0a17764..7ca1978b2031 100644
--- a/services/core/java/com/android/server/pm/AppsFilterBase.java
+++ b/services/core/java/com/android/server/pm/AppsFilterBase.java
@@ -321,6 +321,9 @@ public abstract class AppsFilterBase implements AppsFilterSnapshot {
|| targetPkgSetting.getAppId() < Process.FIRST_APPLICATION_UID
|| callingAppId == targetPkgSetting.getAppId()) {
return false;
+ } else if (Process.isSdkSandboxUid(callingAppId)) {
+ // we only allow sdk sandbox processes access to forcequeryable packages
+ return !isForceQueryable(targetPkgSetting.getAppId());
}
if (mCacheReady) { // use cache
if (!shouldFilterApplicationUsingCache(callingUid,
diff --git a/services/core/java/com/android/server/pm/FileInstallArgs.java b/services/core/java/com/android/server/pm/FileInstallArgs.java
index e3ceccd1abb8..85c3cc91ecf0 100644
--- a/services/core/java/com/android/server/pm/FileInstallArgs.java
+++ b/services/core/java/com/android/server/pm/FileInstallArgs.java
@@ -172,22 +172,9 @@ class FileInstallArgs extends InstallArgs {
return false;
}
- if (onIncremental) {
- Slog.i(TAG, PackageManagerServiceUtils.SELINUX_BUG
- + ": Skipping restorecon for Incremental install of " + beforeCodeFile);
- } else {
- try {
- if (!SELinux.restoreconRecursive(afterCodeFile)) {
- Slog.w(TAG, "Failed to restorecon");
- return false;
- }
- PackageManagerServiceUtils.verifySelinuxLabels(afterCodeFile.getAbsolutePath());
- } catch (Exception e) {
- Slog.e(TAG,
- PackageManagerServiceUtils.SELINUX_BUG + ": Exception from restorecon on "
- + beforeCodeFile, e);
- throw e;
- }
+ if (!onIncremental && !SELinux.restoreconRecursive(afterCodeFile)) {
+ Slog.w(TAG, "Failed to restorecon");
+ return false;
}
// Reflect the rename internally
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index c710120ca437..e62f35d591fa 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -653,10 +653,6 @@ final class InstallPackageHelper {
Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package=" + res.mPkg);
}
- if (res.mPkg != null) {
- PackageManagerServiceUtils.verifySelinuxLabels(res.mPkg.getPath());
- }
-
// A restore should be requested at this point if (a) the install
// succeeded, (b) the operation is not an update.
final boolean update = res.mRemovedInfo != null
@@ -3580,7 +3576,6 @@ final class InstallPackageHelper {
@ParsingPackageUtils.ParseFlags int parseFlags,
@PackageManagerService.ScanFlags int scanFlags,
@Nullable UserHandle user) throws PackageManagerException {
- PackageManagerServiceUtils.verifySelinuxLabels(parsedPackage.getPath());
final Pair<ScanResult, Boolean> scanResultPair = scanSystemPackageLI(
parsedPackage, parseFlags, scanFlags, user);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 7c900ef9401a..37bfbb11948a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2837,6 +2837,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (!stagedSplits.contains(null)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Full install must include a base package");
+ } else if ((params.installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
+ EventLog.writeEvent(0x534e4554, "219044664");
+
+ // Installing base.apk. Make sure the app is restarted.
+ params.setDontKillApp(false);
}
if (baseApk.isSplitRequired() && (stagedSplits.size() <= 1
|| !stagedSplitTypes.containsAll(requiredSplitTypes))) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 621ad5223de2..4f8c792d3b49 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -803,6 +803,13 @@ public class PackageManagerService implements PackageSender, TestUtilityService
private AndroidPackage mPlatformPackage;
ComponentName mCustomResolverComponentName;
+ // Recorded overlay paths configuration for the Android app info.
+ private String[] mPlatformPackageOverlayPaths = null;
+ private String[] mPlatformPackageOverlayResourceDirs = null;
+ // And the same paths for the replaced resolver activity package
+ private String[] mReplacedResolverPackageOverlayPaths = null;
+ private String[] mReplacedResolverPackageOverlayResourceDirs = null;
+
private boolean mResolverReplaced = false;
@NonNull
@@ -6562,11 +6569,61 @@ public class PackageManagerService implements PackageSender, TestUtilityService
});
}
+ if (userId == UserHandle.USER_SYSTEM) {
+ // Keep the overlays in the system application info (and anything special cased as well)
+ // up to date to make sure system ui is themed correctly.
+ maybeUpdateSystemOverlays(targetPackageName, newOverlayPaths);
+ }
+
invalidatePackageInfoCache();
return true;
}
+ private void maybeUpdateSystemOverlays(String targetPackageName, OverlayPaths newOverlayPaths) {
+ if (!mResolverReplaced) {
+ if (targetPackageName.equals("android")) {
+ if (newOverlayPaths == null) {
+ mPlatformPackageOverlayPaths = null;
+ mPlatformPackageOverlayResourceDirs = null;
+ } else {
+ mPlatformPackageOverlayPaths = newOverlayPaths.getOverlayPaths().toArray(
+ new String[0]);
+ mPlatformPackageOverlayResourceDirs = newOverlayPaths.getResourceDirs().toArray(
+ new String[0]);
+ }
+ applyUpdatedSystemOverlayPaths();
+ }
+ } else {
+ if (targetPackageName.equals(mResolveActivity.applicationInfo.packageName)) {
+ if (newOverlayPaths == null) {
+ mReplacedResolverPackageOverlayPaths = null;
+ mReplacedResolverPackageOverlayResourceDirs = null;
+ } else {
+ mReplacedResolverPackageOverlayPaths =
+ newOverlayPaths.getOverlayPaths().toArray(new String[0]);
+ mReplacedResolverPackageOverlayResourceDirs =
+ newOverlayPaths.getResourceDirs().toArray(new String[0]);
+ }
+ applyUpdatedSystemOverlayPaths();
+ }
+ }
+ }
+
+ private void applyUpdatedSystemOverlayPaths() {
+ if (mAndroidApplication == null) {
+ Slog.i(TAG, "Skipped the AndroidApplication overlay paths update - no app yet");
+ } else {
+ mAndroidApplication.overlayPaths = mPlatformPackageOverlayPaths;
+ mAndroidApplication.resourceDirs = mPlatformPackageOverlayResourceDirs;
+ }
+ if (mResolverReplaced) {
+ mResolveActivity.applicationInfo.overlayPaths = mReplacedResolverPackageOverlayPaths;
+ mResolveActivity.applicationInfo.resourceDirs =
+ mReplacedResolverPackageOverlayResourceDirs;
+ }
+ }
+
private void enforceAdjustRuntimePermissionsPolicyOrUpgradeRuntimePermissions(
@NonNull String message) {
if (mContext.checkCallingOrSelfPermission(
@@ -7043,6 +7100,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
PackageManagerService.onChanged();
}
+ applyUpdatedSystemOverlayPaths();
}
ApplicationInfo getCoreAndroidApplication() {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 719c3b767b46..3443d455ee82 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -36,6 +36,7 @@ import static com.android.server.pm.PackageManagerService.TAG;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.Context;
@@ -61,7 +62,6 @@ import android.os.Debug;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Process;
-import android.os.SELinux;
import android.os.SystemProperties;
import android.os.incremental.IncrementalManager;
import android.os.incremental.IncrementalStorage;
@@ -1089,12 +1089,6 @@ public class PackageManagerServiceUtils {
PlatformCompat compat, ComponentResolverApi resolver,
List<ResolveInfo> resolveInfos, boolean isReceiver,
Intent intent, String resolvedType, int filterCallingUid) {
- // Do not enforce filter matching when the caller is system or root.
- // see ActivityManager#checkComponentPermission(String, int, int, boolean)
- if (filterCallingUid == Process.ROOT_UID || filterCallingUid == Process.SYSTEM_UID) {
- return;
- }
-
final Printer logPrinter = DEBUG_INTENT_MATCHING
? new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM)
: null;
@@ -1102,8 +1096,9 @@ public class PackageManagerServiceUtils {
for (int i = resolveInfos.size() - 1; i >= 0; --i) {
final ComponentInfo info = resolveInfos.get(i).getComponentInfo();
- // Do not enforce filter matching when the caller is the same app
- if (info.applicationInfo.uid == filterCallingUid) {
+ // Do not enforce filter matching when the caller is system, root, or the same app
+ if (ActivityManager.checkComponentPermission(null, filterCallingUid,
+ info.applicationInfo.uid, false) == PackageManager.PERMISSION_GRANTED) {
continue;
}
@@ -1407,28 +1402,4 @@ public class PackageManagerServiceUtils {
}
}
}
-
- // TODO(b/231951809): remove this workaround after figuring out why apk_tmp_file labels stay
- // on the installed apps instead of the correct apk_data_file ones
-
- public static final String SELINUX_BUG = "b/231951809";
-
- /**
- * A workaround for b/231951809:
- * Verifies the SELinux labels of the passed path, and tries to correct them if detects them
- * wrong or missing.
- */
- public static void verifySelinuxLabels(String path) {
- final String expectedCon = SELinux.fileSelabelLookup(path);
- final String actualCon = SELinux.getFileContext(path);
- Slog.i(TAG, SELINUX_BUG + ": checking selinux labels for " + path + " expected / actual: "
- + expectedCon + " / " + actualCon);
- if (expectedCon == null || !expectedCon.equals(actualCon)) {
- Slog.w(TAG, SELINUX_BUG + ": labels don't match, reapplying for " + path);
- if (!SELinux.restoreconRecursive(new File(path))) {
- Slog.w(TAG, SELINUX_BUG + ": Failed to reapply restorecon");
- }
- // well, if it didn't work now after not working at first, not much else can be done
- }
- }
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index fa0c6c393cdc..0c601bfde05a 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -706,7 +706,7 @@ class ShortcutPackage extends ShortcutPackageItem {
}
pinnedShortcuts.addAll(pinned);
});
- // Then, update the pinned state if necessary.
+ // Secondly, update the pinned state if necessary.
final List<ShortcutInfo> pinned = findAll(pinnedShortcuts);
if (pinned != null) {
pinned.forEach(si -> {
@@ -720,6 +720,8 @@ class ShortcutPackage extends ShortcutPackageItem {
si.clearFlags(ShortcutInfo.FLAG_PINNED);
}
});
+ // Then, schedule a background job to persist the pinned states.
+ mShortcutUser.forAllLaunchers(ShortcutPackageItem::scheduleSave);
// Lastly, remove the ones that are no longer pinned, cached nor dynamic.
removeOrphans();
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index a83cb5e37ba2..2c1be72e02f0 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -966,8 +966,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final PackageManagerInternal packageManagerInternal = LocalServices.getService(
PackageManagerInternal.class);
- if (packageManagerInternal.getPackageUid(source.getPackageName(), 0,
- UserHandle.getUserId(callingUid)) != source.getUid()) {
+
+ // TODO(b/234653108): Clean up this UID/package & cross-user check.
+ // If calling from the system process, allow registering attribution for package from
+ // any user
+ int userId = UserHandle.getUserId((callingUid == Process.SYSTEM_UID ? source.getUid()
+ : callingUid));
+ if (packageManagerInternal.getPackageUid(source.getPackageName(), 0, userId)
+ != source.getUid()) {
throw new SecurityException("Cannot register attribution source for package:"
+ source.getPackageName() + " from uid:" + callingUid);
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 11fd99cf5b68..b00d8b47906a 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -144,11 +144,11 @@ public interface StatusBarManagerInternal {
/**
* @see com.android.internal.statusbar.IStatusBar#showToast(String, IBinder, CharSequence,
- * IBinder, int, ITransientNotificationCallback)
+ * IBinder, int, ITransientNotificationCallback, int)
*/
void showToast(int uid, String packageName, IBinder token, CharSequence text,
IBinder windowToken, int duration,
- @Nullable ITransientNotificationCallback textCallback);
+ @Nullable ITransientNotificationCallback textCallback, int displayId);
/** @see com.android.internal.statusbar.IStatusBar#hideToast(String, IBinder) */
void hideToast(String packageName, IBinder token);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index d48f26332017..46e7574e1c8a 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -631,10 +631,11 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
@Override
public void showToast(int uid, String packageName, IBinder token, CharSequence text,
IBinder windowToken, int duration,
- @Nullable ITransientNotificationCallback callback) {
+ @Nullable ITransientNotificationCallback callback, int displayId) {
if (mBar != null) {
try {
- mBar.showToast(uid, packageName, token, text, windowToken, duration, callback);
+ mBar.showToast(uid, packageName, token, text, windowToken, duration, callback,
+ displayId);
} catch (RemoteException ex) { }
}
}
diff --git a/services/core/java/com/android/server/testharness/OWNERS b/services/core/java/com/android/server/testharness/OWNERS
new file mode 100644
index 000000000000..ffbbeb9312b9
--- /dev/null
+++ b/services/core/java/com/android/server/testharness/OWNERS
@@ -0,0 +1 @@
+williamhester@google.com
diff --git a/services/core/java/com/android/server/testharness/TestHarnessModeService.java b/services/core/java/com/android/server/testharness/TestHarnessModeService.java
index 8b2b8b1cfbac..b6a413524c5c 100644
--- a/services/core/java/com/android/server/testharness/TestHarnessModeService.java
+++ b/services/core/java/com/android/server/testharness/TestHarnessModeService.java
@@ -69,8 +69,8 @@ import java.util.Set;
* automatic updates, etc.) are all disabled by default but may be re-enabled by the user.
*/
public class TestHarnessModeService extends SystemService {
+ public static final String TEST_HARNESS_MODE_PROPERTY = "persist.sys.test_harness";
private static final String TAG = TestHarnessModeService.class.getSimpleName();
- private static final String TEST_HARNESS_MODE_PROPERTY = "persist.sys.test_harness";
private PersistentDataBlockManagerInternal mPersistentDataBlockManagerInternal;
@@ -168,9 +168,9 @@ public class TestHarnessModeService extends SystemService {
Slog.d(TAG, "Restarted adbd");
}
- // Disable the TTL for ADB keys before enabling ADB
+ // Disable the TTL for ADB keys before ADB is enabled as a part of AdbService's
+ // initialization.
Settings.Global.putLong(cr, Settings.Global.ADB_ALLOWED_CONNECTION_TIME, 0);
- Settings.Global.putInt(cr, Settings.Global.ADB_ENABLED, 1);
Settings.Global.putInt(cr, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
Settings.Global.putInt(cr, Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 0);
Settings.Global.putInt(
diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
index 6e5011dacd82..3b4aa8e6b701 100644
--- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
+++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
@@ -154,7 +154,7 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
for (InputWindowHandle window : windowHandles) {
final boolean visible = (window.inputConfig & InputConfig.NOT_VISIBLE) == 0;
- if (visible && window.getWindow() != null) {
+ if (visible && window.getWindow() != null && !window.isClone) {
tempVisibleWindows.add(window);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index e700103bf0d2..398926f0ca85 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -432,6 +432,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private static final int DESTROY_TIMEOUT = 10 * 1000;
final ActivityTaskManagerService mAtmService;
+ @NonNull
final ActivityInfo info; // activity info provided by developer in AndroidManifest
// Which user is this running for?
final int mUserId;
@@ -670,9 +671,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* from the style of activity. Because we don't want {@link WindowContainer#getOrientation()}
* to be affected by the temporal state of {@link ActivityClientController#convertToTranslucent}
* when running ANIM_SCENE_TRANSITION.
- * @see WindowContainer#fillsParent()
+ * @see WindowContainer#providesOrientation()
*/
- private final boolean mFillsParent;
+ private final boolean mStyleFillsParent;
// The input dispatching timeout for this application token in milliseconds.
long mInputDispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
@@ -1971,10 +1972,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// This style is propagated to the main window attributes with
// FLAG_SHOW_WALLPAPER from PhoneWindow#generateLayout.
|| ent.array.getBoolean(R.styleable.Window_windowShowWallpaper, false);
- mFillsParent = mOccludesParent;
+ mStyleFillsParent = mOccludesParent;
noDisplay = ent.array.getBoolean(R.styleable.Window_windowNoDisplay, false);
} else {
- mFillsParent = mOccludesParent = true;
+ mStyleFillsParent = mOccludesParent = true;
noDisplay = false;
}
@@ -2786,7 +2787,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@VisibleForTesting
boolean canLaunchHomeActivity(int uid, ActivityRecord sourceRecord) {
- if (uid == Process.myUid() || uid == 0) {
+ if (uid == SYSTEM_UID || uid == 0) {
// System process can launch home activity.
return true;
}
@@ -2880,8 +2881,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
@Override
+ boolean providesOrientation() {
+ return mStyleFillsParent;
+ }
+
+ @Override
boolean fillsParent() {
- return mFillsParent;
+ return occludesParent(true /* includingFinishing */);
}
/** Returns true if this activity is not finishing, is opaque and fills the entire space of
@@ -7860,7 +7866,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Vertical position
int offsetY = 0;
if (parentBounds.height() != screenResolvedBounds.height()) {
-
if (screenResolvedBounds.height() >= parentAppBounds.height()) {
// If resolved bounds overlap with insets, center within app bounds.
offsetY = getCenterOffset(
@@ -7908,6 +7913,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return mLetterboxBoundsForFixedOrientationAndAspectRatio != null;
}
+ boolean isAspectRatioApplied() {
+ return mIsAspectRatioApplied;
+ }
+
/**
* Whether this activity is eligible for letterbox eduction.
*
@@ -8079,7 +8088,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
resolvedBounds.set(containingBounds);
final float letterboxAspectRatioOverride =
- mLetterboxUiController.getFixedOrientationLetterboxAspectRatio(newParentConfig);
+ mWmService.mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
final float desiredAspectRatio =
letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
? letterboxAspectRatioOverride : computeAspectRatio(parentBounds);
@@ -8632,7 +8641,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* Returns the min aspect ratio of this activity.
*/
private float getMinAspectRatio() {
- return info.getMinAspectRatio(getRequestedOrientation());
+ float infoAspectRatio = info.getMinAspectRatio(getRequestedOrientation());
+ // Complying with the CDD 7.1.1.2 requirement for unresizble apps:
+ // https://source.android.com/compatibility/12/android-12-cdd#7112_screen_aspect_ratio
+ return infoAspectRatio < 1f && info.resizeMode == RESIZE_MODE_UNRESIZEABLE
+ // TODO(233582832): Consider removing fixed-orientation condition.
+ // Some apps switching from tablet to phone layout at the certain size
+ // threshold. This may lead to flickering on tablets in landscape orientation
+ // if an app sets orientation to portrait dynamically because of aspect ratio
+ // restriction applied here.
+ && getRequestedConfigurationOrientation() != ORIENTATION_UNDEFINED
+ ? mLetterboxUiController.getDefaultMinAspectRatioForUnresizableApps()
+ : infoAspectRatio;
}
/**
@@ -9692,6 +9712,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return true;
}
+ @Nullable
+ Point getMinDimensions() {
+ final ActivityInfo.WindowLayout windowLayout = info.windowLayout;
+ if (windowLayout == null) {
+ return null;
+ }
+ return new Point(windowLayout.minWidth, windowLayout.minHeight);
+ }
+
static class Builder {
private final ActivityTaskManagerService mAtmService;
private WindowProcessController mCallerApp;
diff --git a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
index fc22e2decbef..d59f69622f15 100644
--- a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
+++ b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
@@ -19,7 +19,6 @@ package com.android.server.wm;
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.os.InputConfig;
-import android.os.Process;
import android.view.InputWindowHandle;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -102,8 +101,8 @@ class ActivityRecordInputSink {
inputWindowHandle.replaceTouchableRegionWithCrop = true;
inputWindowHandle.name = mName;
inputWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
- inputWindowHandle.ownerUid = Process.myUid();
- inputWindowHandle.ownerPid = Process.myPid();
+ inputWindowHandle.ownerPid = WindowManagerService.MY_PID;
+ inputWindowHandle.ownerUid = WindowManagerService.MY_UID;
inputWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.NO_INPUT_CHANNEL;
return inputWindowHandle;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 4e2d1aa803af..a78dbd6bbe60 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -518,7 +518,8 @@ public class ActivityStartController {
*/
int startActivityInTaskFragment(@NonNull TaskFragment taskFragment,
@NonNull Intent activityIntent, @Nullable Bundle activityOptions,
- @Nullable IBinder resultTo, int callingUid, int callingPid) {
+ @Nullable IBinder resultTo, int callingUid, int callingPid,
+ @Nullable IBinder errorCallbackToken) {
final ActivityRecord caller =
resultTo != null ? ActivityRecord.forTokenLocked(resultTo) : null;
return obtainStarter(activityIntent, "startActivityInTaskFragment")
@@ -531,6 +532,7 @@ public class ActivityStartController {
.setRealCallingUid(callingUid)
.setRealCallingPid(callingPid)
.setUserId(caller != null ? caller.mUserId : mService.getCurrentUserId())
+ .setErrorCallbackToken(errorCallbackToken)
.execute();
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index a4f6eaae2fbe..a30c7445225b 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -51,6 +51,7 @@ import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
+import static android.content.pm.ActivityInfo.launchModeToString;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.INVALID_UID;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -89,7 +90,6 @@ import android.app.PendingIntent;
import android.app.ProfilerInfo;
import android.app.WaitResult;
import android.app.WindowConfiguration;
-import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.ComponentName;
@@ -192,6 +192,7 @@ class ActivityStarter {
private Task mInTask;
private TaskFragment mInTaskFragment;
+ private TaskFragment mAddingToTaskFragment;
@VisibleForTesting
boolean mAddingToTask;
@@ -211,6 +212,7 @@ class ActivityStarter {
// The task which was above the targetTask before starting this activity. null if the targetTask
// was already on top or if the activity is in a new task.
private Task mPriorAboveTask;
+ private boolean mDisplayLockAndOccluded;
// We must track when we deliver the new intent since multiple code paths invoke
// {@link #deliverNewIntent}. This is due to early returns in the code path. This flag is used
@@ -368,6 +370,13 @@ class ActivityStarter {
int filterCallingUid;
PendingIntentRecord originatingPendingIntent;
boolean allowBackgroundActivityStart;
+ /**
+ * The error callback token passed in {@link android.window.WindowContainerTransaction}
+ * for TaskFragment operation error handling via
+ * {@link android.window.TaskFragmentOrganizer#onTaskFragmentError(IBinder, Throwable)}.
+ */
+ @Nullable
+ IBinder errorCallbackToken;
/**
* If set to {@code true}, allows this activity start to look into
@@ -421,6 +430,7 @@ class ActivityStarter {
filterCallingUid = UserHandle.USER_NULL;
originatingPendingIntent = null;
allowBackgroundActivityStart = false;
+ errorCallbackToken = null;
}
/**
@@ -463,6 +473,7 @@ class ActivityStarter {
filterCallingUid = request.filterCallingUid;
originatingPendingIntent = request.originatingPendingIntent;
allowBackgroundActivityStart = request.allowBackgroundActivityStart;
+ errorCallbackToken = request.errorCallbackToken;
}
/**
@@ -1692,7 +1703,8 @@ class ActivityStarter {
// Root task should also be detached from display and be removed if it's empty.
if (startedActivityRootTask != null && startedActivityRootTask.isAttached()
&& !startedActivityRootTask.hasActivity()
- && !startedActivityRootTask.isActivityTypeHome()) {
+ && !startedActivityRootTask.isActivityTypeHome()
+ && !startedActivityRootTask.mCreatedByOrganizer) {
startedActivityRootTask.removeIfPossible("handleStartResult");
}
if (newTransition != null) {
@@ -1733,19 +1745,38 @@ class ActivityStarter {
// Transition housekeeping.
final TransitionController transitionController = started.mTransitionController;
final boolean isStarted = result == START_SUCCESS || result == START_TASK_TO_FRONT;
+ final boolean isTransientLaunch = options != null && options.getTransientLaunch();
+ // Start transient launch while keyguard locked and occluded by other app, for this
+ // condition we would like to play the remote transition without modify any visible state
+ // for the hierarchy in core, so here will force execute this transition.
+ final boolean forceTransientTransition = isTransientLaunch && mPriorAboveTask != null
+ && mDisplayLockAndOccluded;
if (isStarted) {
// The activity is started new rather than just brought forward, so record it as an
// existence change.
transitionController.collectExistenceChange(started);
} else if (result == START_DELIVERED_TO_TOP && newTransition != null) {
// We just delivered to top, so there isn't an actual transition here.
- newTransition.abort();
- newTransition = null;
+ if (!forceTransientTransition) {
+ newTransition.abort();
+ newTransition = null;
+ }
}
- if (options != null && options.getTransientLaunch()) {
+ if (isTransientLaunch) {
+ if (forceTransientTransition && newTransition != null) {
+ newTransition.collect(mLastStartActivityRecord);
+ newTransition.collect(mPriorAboveTask);
+ }
// `started` isn't guaranteed to be the actual relevant activity, so we must wait
// until after we launched to identify the relevant activity.
transitionController.setTransientLaunch(mLastStartActivityRecord, mPriorAboveTask);
+ if (forceTransientTransition && newTransition != null) {
+ final DisplayContent dc = mLastStartActivityRecord.getDisplayContent();
+ // update wallpaper target to TransientHide
+ dc.mWallpaperController.adjustWallpaperWindows();
+ // execute transition because there is no change
+ newTransition.setReady(dc, true /* ready */);
+ }
}
if (!userLeaving) {
// no-user-leaving implies not entering PiP.
@@ -2041,8 +2072,20 @@ class ActivityStarter {
}
if (mInTaskFragment != null && !canEmbedActivity(mInTaskFragment, r, newTask, targetTask)) {
- Slog.e(TAG, "Permission denied: Cannot embed " + r + " to " + mInTaskFragment.getTask()
- + " targetTask= " + targetTask);
+ final StringBuilder errorMsg = new StringBuilder("Permission denied: Cannot embed " + r
+ + " to " + mInTaskFragment.getTask() + ". newTask=" + newTask + ", targetTask= "
+ + targetTask);
+ if (newTask && isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE,
+ LAUNCH_SINGLE_INSTANCE_PER_TASK, LAUNCH_SINGLE_TASK)) {
+ errorMsg.append("\nActivity tries to launch on a new task because the launch mode"
+ + " is " + launchModeToString(mLaunchMode));
+ } else if (newTask && (mLaunchFlags & (FLAG_ACTIVITY_NEW_DOCUMENT
+ | FLAG_ACTIVITY_NEW_TASK)) != 0) {
+ errorMsg.append("\nActivity tries to launch on a new task because the launch flags"
+ + " contains FLAG_ACTIVITY_NEW_DOCUMENT or FLAG_ACTIVITY_NEW_TASK. "
+ + "mLaunchFlag=" + mLaunchFlags);
+ }
+ Slog.e(TAG, errorMsg.toString());
return START_PERMISSION_DENIED;
}
@@ -2265,20 +2308,27 @@ class ActivityStarter {
// In this situation we want to remove all activities from the task up to the one
// being started. In most cases this means we are resetting the task to its initial
// state.
- final ActivityRecord top = targetTask.performClearTop(mStartActivity, mLaunchFlags);
+ final ActivityRecord clearTop = targetTask.performClearTop(mStartActivity,
+ mLaunchFlags);
- if (top != null) {
- if (top.isRootOfTask()) {
+ if (clearTop != null && !clearTop.finishing) {
+ if (clearTop.isRootOfTask()) {
// Activity aliases may mean we use different intents for the top activity,
// so make sure the task now has the identity of the new intent.
- top.getTask().setIntent(mStartActivity);
+ clearTop.getTask().setIntent(mStartActivity);
}
- deliverNewIntent(top, intentGrants);
+ deliverNewIntent(clearTop, intentGrants);
} else {
// A special case: we need to start the activity because it is not currently
// running, and the caller has asked to clear the current task to have this
// activity at the top.
mAddingToTask = true;
+ // Adding the new activity to the same embedded TF of the clear-top activity if
+ // possible.
+ if (clearTop != null && clearTop.getTaskFragment() != null
+ && clearTop.getTaskFragment().isEmbedded()) {
+ mAddingToTaskFragment = clearTop.getTaskFragment();
+ }
if (targetTask.getRootTask() == null) {
// Target root task got cleared when we all activities were removed above.
// Go ahead and reset it.
@@ -2383,6 +2433,7 @@ class ActivityStarter {
mAvoidMoveToFront = false;
mFrozeTaskList = false;
mTransientLaunch = false;
+ mDisplayLockAndOccluded = false;
mVoiceSession = null;
mVoiceInteractor = null;
@@ -2491,6 +2542,16 @@ class ActivityStarter {
mAvoidMoveToFront = true;
}
mTransientLaunch = mOptions.getTransientLaunch();
+ final KeyguardController kc = mSupervisor.getKeyguardController();
+ final int displayId = mPreferredTaskDisplayArea.getDisplayId();
+ mDisplayLockAndOccluded = kc.isKeyguardLocked(displayId)
+ && kc.isDisplayOccluded(displayId);
+ // Recents animation on lock screen, do not resume & move launcher to top.
+ if (mTransientLaunch && mDisplayLockAndOccluded
+ && mService.getTransitionController().isShellTransitionsEnabled()) {
+ mDoResume = false;
+ mAvoidMoveToFront = true;
+ }
mTargetRootTask = Task.fromWindowContainerToken(mOptions.getLaunchRootTask());
if (inTaskFragment == null) {
@@ -2895,6 +2956,7 @@ class ActivityStarter {
private void addOrReparentStartingActivity(@NonNull Task task, String reason) {
TaskFragment newParent = task;
if (mInTaskFragment != null) {
+ // TODO(b/234351413): remove remaining embedded Task logic.
// mInTaskFragment is created and added to the leaf task by task fragment organizer's
// request. If the task was resolved and different than mInTaskFragment, reparent the
// task to mInTaskFragment for embedding.
@@ -2906,17 +2968,29 @@ class ActivityStarter {
newParent = mInTaskFragment;
}
} else {
- final ActivityRecord top = task.topRunningActivity(false /* focusableOnly */,
- false /* includingEmbeddedTask */);
- final TaskFragment taskFragment = top != null ? top.getTaskFragment() : null;
- if (taskFragment != null && taskFragment.isEmbedded()
- && canEmbedActivity(taskFragment, mStartActivity, false /* newTask */, task)) {
+ TaskFragment candidateTf = mAddingToTaskFragment != null ? mAddingToTaskFragment : null;
+ if (candidateTf == null) {
+ final ActivityRecord top = task.topRunningActivity(false /* focusableOnly */,
+ false /* includingEmbeddedTask */);
+ if (top != null) {
+ candidateTf = top.getTaskFragment();
+ }
+ }
+ if (candidateTf != null && candidateTf.isEmbedded()
+ && canEmbedActivity(candidateTf, mStartActivity, false /* newTask */, task)) {
// Use the embedded TaskFragment of the top activity as the new parent if the
// activity can be embedded.
- newParent = top.getTaskFragment();
+ newParent = candidateTf;
}
}
-
+ // Start Activity to the Task if mStartActivity's min dimensions are not satisfied.
+ if (newParent.isEmbedded() && newParent.smallerThanMinDimension(mStartActivity)) {
+ reason += " - MinimumDimensionViolation";
+ mService.mWindowOrganizerController.sendMinimumDimensionViolation(
+ newParent, mStartActivity.getMinDimensions(), mRequest.errorCallbackToken,
+ reason);
+ newParent = task;
+ }
if (mStartActivity.getTaskFragment() == null
|| mStartActivity.getTaskFragment() == newParent) {
newParent.addChild(mStartActivity, POSITION_TOP);
@@ -3201,6 +3275,11 @@ class ActivityStarter {
return this;
}
+ ActivityStarter setErrorCallbackToken(@Nullable IBinder errorCallbackToken) {
+ mRequest.errorCallbackToken = errorCallbackToken;
+ return this;
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix);
pw.print("mCurrentUser=");
@@ -3235,12 +3314,8 @@ class ActivityStarter {
pw.println(mOptions);
}
pw.print(prefix);
- pw.print("mLaunchSingleTop=");
- pw.print(LAUNCH_SINGLE_TOP == mLaunchMode);
- pw.print(" mLaunchSingleInstance=");
- pw.print(LAUNCH_SINGLE_INSTANCE == mLaunchMode);
- pw.print(" mLaunchSingleTask=");
- pw.println(LAUNCH_SINGLE_TASK == mLaunchMode);
+ pw.print("mLaunchMode=");
+ pw.print(launchModeToString(mLaunchMode));
pw.print(prefix);
pw.print("mLaunchFlags=0x");
pw.print(Integer.toHexString(mLaunchFlags));
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index e5c09131ee69..6ae8887a7912 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -73,7 +73,6 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IMMERSIVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
import static com.android.server.am.ActivityManagerService.ANR_TRACE_DIR;
-import static com.android.server.am.ActivityManagerService.MY_PID;
import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS;
import static com.android.server.am.ActivityManagerService.dumpStackTraces;
import static com.android.server.am.ActivityManagerServiceDumpActivitiesProto.ROOT_WINDOW_CONTAINER;
@@ -117,6 +116,7 @@ import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_O
import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_ONLY;
import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
import static com.android.server.wm.Task.REPARENT_KEEP_ROOT_TASK_AT_FRONT;
+import static com.android.server.wm.WindowManagerService.MY_PID;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import android.Manifest;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 3e8e080ebb27..bd2ce95a814f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -42,6 +42,7 @@ import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static android.os.Process.INVALID_UID;
+import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -122,7 +123,6 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
-import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
@@ -1321,7 +1321,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
}
void acquireLaunchWakelock() {
- if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) {
+ if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != SYSTEM_UID) {
throw new IllegalStateException("Calling must be system uid");
}
mLaunchingActivityWakeLock.acquire();
@@ -1394,8 +1394,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
if (mLaunchingActivityWakeLock.isHeld()) {
mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
- if (VALIDATE_WAKE_LOCK_CALLER &&
- Binder.getCallingUid() != Process.myUid()) {
+ if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != SYSTEM_UID) {
throw new IllegalStateException("Calling must be system uid");
}
mLaunchingActivityWakeLock.release();
@@ -1805,7 +1804,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
if (!mGoingToSleepWakeLock.isHeld()) {
mGoingToSleepWakeLock.acquire();
if (mLaunchingActivityWakeLock.isHeld()) {
- if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) {
+ if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != SYSTEM_UID) {
throw new IllegalStateException("Calling must be system uid");
}
mLaunchingActivityWakeLock.release();
@@ -2466,8 +2465,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
case LAUNCH_TIMEOUT_MSG: {
if (mLaunchingActivityWakeLock.isHeld()) {
Slog.w(TAG, "Launch timeout has expired, giving up wake lock!");
- if (VALIDATE_WAKE_LOCK_CALLER
- && Binder.getCallingUid() != Process.myUid()) {
+ if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != SYSTEM_UID) {
throw new IllegalStateException("Calling must be system uid");
}
mLaunchingActivityWakeLock.release();
diff --git a/services/core/java/com/android/server/wm/AnrController.java b/services/core/java/com/android/server/wm/AnrController.java
index 6befefda8a12..b23f50154257 100644
--- a/services/core/java/com/android/server/wm/AnrController.java
+++ b/services/core/java/com/android/server/wm/AnrController.java
@@ -256,7 +256,7 @@ class AnrController {
Slog.i(TAG_WM, "Pre-dump for unresponsive");
final ArrayList<Integer> firstPids = new ArrayList<>(1);
- firstPids.add(ActivityManagerService.MY_PID);
+ firstPids.add(WindowManagerService.MY_PID);
ArrayList<Integer> nativePids = null;
final int[] pids = shouldDumpSf[0]
? Process.getPidsForCommands(new String[] { "/system/bin/surfaceflinger" })
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index ad3bb2dcc322..fbb7dac30ef3 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -79,6 +79,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Trace;
import android.util.ArrayMap;
@@ -148,7 +149,8 @@ public class AppTransitionController {
* Returns the currently visible window that is associated with the wallpaper in case we are
* transitioning from an activity with a wallpaper to one without.
*/
- private @Nullable WindowState getOldWallpaper() {
+ @Nullable
+ private WindowState getOldWallpaper() {
final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
final @TransitionType int firstTransit =
mDisplayContent.mAppTransition.getFirstAppTransition();
@@ -168,6 +170,16 @@ public class AppTransitionController {
? null : wallpaperTarget;
}
+ @NonNull
+ private static ArraySet<ActivityRecord> getAppsForAnimation(
+ @NonNull ArraySet<ActivityRecord> apps, boolean excludeLauncherFromAnimation) {
+ final ArraySet<ActivityRecord> appsForAnimation = new ArraySet<>(apps);
+ if (excludeLauncherFromAnimation) {
+ appsForAnimation.removeIf(ConfigurationContainer::isActivityTypeHome);
+ }
+ return appsForAnimation;
+ }
+
/**
* Handle application transition for given display.
*/
@@ -217,18 +229,29 @@ public class AppTransitionController {
mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(
mDisplayContent.mOpeningApps);
- final @TransitionOldType int transit = getTransitCompatType(
- mDisplayContent.mAppTransition, mDisplayContent.mOpeningApps,
- mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers,
+ // Remove launcher from app transition animation while recents is running. Recents animation
+ // is managed outside of app transition framework, so we just need to commit visibility.
+ final boolean excludeLauncherFromAnimation =
+ mDisplayContent.mOpeningApps.stream().anyMatch(
+ (app) -> app.isAnimating(PARENTS, ANIMATION_TYPE_RECENTS))
+ || mDisplayContent.mClosingApps.stream().anyMatch(
+ (app) -> app.isAnimating(PARENTS, ANIMATION_TYPE_RECENTS));
+ final ArraySet<ActivityRecord> openingAppsForAnimation = getAppsForAnimation(
+ mDisplayContent.mOpeningApps, excludeLauncherFromAnimation);
+ final ArraySet<ActivityRecord> closingAppsForAnimation = getAppsForAnimation(
+ mDisplayContent.mClosingApps, excludeLauncherFromAnimation);
+
+ @TransitionOldType final int transit = getTransitCompatType(
+ mDisplayContent.mAppTransition, openingAppsForAnimation, closingAppsForAnimation,
+ mDisplayContent.mChangingContainers,
mWallpaperControllerLocked.getWallpaperTarget(), getOldWallpaper(),
mDisplayContent.mSkipAppTransitionAnimation);
mDisplayContent.mSkipAppTransitionAnimation = false;
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"handleAppTransitionReady: displayId=%d appTransition={%s}"
- + " openingApps=[%s] closingApps=[%s] transit=%s",
- mDisplayContent.mDisplayId,
- appTransition.toString(),
+ + " excludeLauncherFromAnimation=%b openingApps=[%s] closingApps=[%s] transit=%s",
+ mDisplayContent.mDisplayId, appTransition.toString(), excludeLauncherFromAnimation,
mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
AppTransition.appTransitionOldToString(transit));
@@ -236,13 +259,15 @@ public class AppTransitionController {
// what will control the animation theme. If all closing windows are obscured, then there is
// no need to do an animation. This is the case, for example, when this transition is being
// done behind a dream window.
- final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
- mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers);
- final ActivityRecord animLpActivity = findAnimLayoutParamsToken(transit, activityTypes);
+ final ArraySet<Integer> activityTypes = collectActivityTypes(openingAppsForAnimation,
+ closingAppsForAnimation, mDisplayContent.mChangingContainers);
+ final ActivityRecord animLpActivity = findAnimLayoutParamsToken(transit, activityTypes,
+ openingAppsForAnimation, closingAppsForAnimation,
+ mDisplayContent.mChangingContainers);
final ActivityRecord topOpeningApp =
- getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */);
+ getTopApp(openingAppsForAnimation, false /* ignoreHidden */);
final ActivityRecord topClosingApp =
- getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */);
+ getTopApp(closingAppsForAnimation, false /* ignoreHidden */);
final ActivityRecord topChangingApp =
getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */);
final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
@@ -254,14 +279,14 @@ public class AppTransitionController {
overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
}
- final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mClosingApps)
- || containsVoiceInteraction(mDisplayContent.mOpeningApps);
+ final boolean voiceInteraction = containsVoiceInteraction(closingAppsForAnimation)
+ || containsVoiceInteraction(openingAppsForAnimation);
final int layoutRedo;
mService.mSurfaceAnimationRunner.deferStartingAnimations();
try {
- applyAnimations(mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, transit,
- animLp, voiceInteraction);
+ applyAnimations(openingAppsForAnimation, closingAppsForAnimation, transit, animLp,
+ voiceInteraction);
handleClosingApps();
handleOpeningApps();
handleChangingApps(transit);
@@ -313,7 +338,7 @@ public class AppTransitionController {
* case we are transitioning from an activity with a wallpaper to one
* without. Otherwise null.
*/
- static @TransitionOldType int getTransitCompatType(AppTransition appTransition,
+ @TransitionOldType static int getTransitCompatType(AppTransition appTransition,
ArraySet<ActivityRecord> openingApps, ArraySet<ActivityRecord> closingApps,
ArraySet<WindowContainer> changingContainers, @Nullable WindowState wallpaperTarget,
@Nullable WindowState oldWallpaper, boolean skipAppTransitionAnimation) {
@@ -356,8 +381,8 @@ public class AppTransitionController {
if (skipAppTransitionAnimation) {
return WindowManager.TRANSIT_OLD_UNSET;
}
- final @TransitionFlags int flags = appTransition.getTransitFlags();
- final @TransitionType int firstTransit = appTransition.getFirstAppTransition();
+ @TransitionFlags final int flags = appTransition.getTransitFlags();
+ @TransitionType final int firstTransit = appTransition.getFirstAppTransition();
// Special transitions
// TODO(new-app-transitions): Revisit if those can be rewritten by using flags.
@@ -730,11 +755,9 @@ public class AppTransitionController {
*/
@Nullable
private ActivityRecord findAnimLayoutParamsToken(@TransitionOldType int transit,
- ArraySet<Integer> activityTypes) {
+ ArraySet<Integer> activityTypes, ArraySet<ActivityRecord> openingApps,
+ ArraySet<ActivityRecord> closingApps, ArraySet<WindowContainer> changingApps) {
ActivityRecord result;
- final ArraySet<ActivityRecord> closingApps = mDisplayContent.mClosingApps;
- final ArraySet<ActivityRecord> openingApps = mDisplayContent.mOpeningApps;
- final ArraySet<WindowContainer> changingApps = mDisplayContent.mChangingContainers;
// Remote animations always win, but fullscreen tokens override non-fullscreen tokens.
result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
@@ -1162,11 +1185,6 @@ public class AppTransitionController {
if (activity == null) {
continue;
}
- if (activity.isAnimating(PARENTS, ANIMATION_TYPE_RECENTS)) {
- ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
- "Delaying app transition for recents animation to finish");
- return false;
- }
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"Check opening app=%s: allDrawn=%b startingDisplayed=%b "
+ "startingMoved=%b isRelaunching()=%b startingWindow=%s",
diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java
index 03b18b53012a..b519dadb2031 100644
--- a/services/core/java/com/android/server/wm/AsyncRotationController.java
+++ b/services/core/java/com/android/server/wm/AsyncRotationController.java
@@ -20,7 +20,7 @@ import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLES
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_FIXED_TRANSFORM;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_TOKEN_TRANSFORM;
import android.annotation.IntDef;
import android.os.HandlerExecutor;
@@ -223,7 +223,7 @@ class AsyncRotationController extends FadeAnimationController implements Consume
if (DEBUG) Slog.d(TAG, "finishOp fade-in " + windowToken.getTopChild());
// The previous animation leash will be dropped when preparing fade-in animation, so
// simply apply new animation without restoring the transformation.
- fadeWindowToken(true /* show */, windowToken, ANIMATION_TYPE_FIXED_TRANSFORM);
+ fadeWindowToken(true /* show */, windowToken, ANIMATION_TYPE_TOKEN_TRANSFORM);
} else if (op.mAction == Operation.ACTION_SEAMLESS && mRotator != null
&& op.mLeash != null && op.mLeash.isValid()) {
if (DEBUG) Slog.d(TAG, "finishOp undo seamless " + windowToken.getTopChild());
@@ -297,7 +297,7 @@ class AsyncRotationController extends FadeAnimationController implements Consume
final WindowToken windowToken = mTargetWindowTokens.keyAt(i);
final Operation op = mTargetWindowTokens.valueAt(i);
if (op.mAction == Operation.ACTION_FADE) {
- fadeWindowToken(false /* show */, windowToken, ANIMATION_TYPE_FIXED_TRANSFORM);
+ fadeWindowToken(false /* show */, windowToken, ANIMATION_TYPE_TOKEN_TRANSFORM);
op.mLeash = windowToken.getAnimationLeash();
if (DEBUG) Slog.d(TAG, "Start fade-out " + windowToken.getTopChild());
} else if (op.mAction == Operation.ACTION_SEAMLESS) {
@@ -331,7 +331,7 @@ class AsyncRotationController extends FadeAnimationController implements Consume
mHideImmediately = true;
final Operation op = new Operation(Operation.ACTION_FADE);
mTargetWindowTokens.put(windowToken, op);
- fadeWindowToken(false /* show */, windowToken, ANIMATION_TYPE_FIXED_TRANSFORM);
+ fadeWindowToken(false /* show */, windowToken, ANIMATION_TYPE_TOKEN_TRANSFORM);
op.mLeash = windowToken.getAnimationLeash();
mHideImmediately = original;
if (DEBUG) Slog.d(TAG, "hideImmediately " + windowToken.getTopChild());
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 1ce99c13fa60..a870ed3faa28 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -225,6 +225,7 @@ import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManager.DisplayImePolicy;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
+import android.window.DisplayWindowPolicyController;
import android.window.IDisplayAreaOrganizer;
import android.window.TransitionRequestInfo;
@@ -1980,6 +1981,16 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
/**
+ * @see DisplayWindowPolicyController#canShowTasksInRecents()
+ */
+ boolean canShowTasksInRecents() {
+ if (mDwpcHelper == null) {
+ return true;
+ }
+ return mDwpcHelper.canShowTasksInRecents();
+ }
+
+ /**
* Applies the rotation transaction. This must be called after {@link #updateRotationUnchecked}
* (if it returned {@code true}) to actually finish the rotation.
*
diff --git a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
index 2deb8286f95f..5d4904264056 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
@@ -152,6 +152,16 @@ class DisplayWindowPolicyControllerHelper {
return mDisplayWindowPolicyController.isWindowingModeSupported(windowingMode);
}
+ /**
+ * @see DisplayWindowPolicyController#canShowTasksInRecents()
+ */
+ public final boolean canShowTasksInRecents() {
+ if (mDisplayWindowPolicyController == null) {
+ return true;
+ }
+ return mDisplayWindowPolicyController.canShowTasksInRecents();
+ }
+
void dump(String prefix, PrintWriter pw) {
if (mDisplayWindowPolicyController != null) {
pw.println();
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index c47d778c60bc..73f0d31e1944 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -31,6 +31,8 @@ import static com.android.server.wm.DragDropController.MSG_TEAR_DOWN_DRAG_AND_DR
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.MY_PID;
+import static com.android.server.wm.WindowManagerService.MY_UID;
import android.animation.Animator;
import android.animation.PropertyValuesHolder;
@@ -45,7 +47,6 @@ import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.os.InputConfig;
-import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -207,8 +208,6 @@ class DragState {
// Send drag end broadcast if drag start has been sent.
if (mDragInProgress) {
- final int myPid = Process.myPid();
-
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "broadcasting DRAG_ENDED");
}
@@ -236,7 +235,7 @@ class DragState {
}
// if the current window is in the same process,
// the dispatch has already recycled the event
- if (myPid != ws.mSession.mPid) {
+ if (MY_PID != ws.mSession.mPid) {
event.recycle();
}
}
@@ -320,7 +319,6 @@ class DragState {
mData.fixUris(mSourceUserId);
}
}
- final int myPid = Process.myPid();
final IBinder clientToken = touchedWin.mClient.asBinder();
final DragEvent event = obtainDragEvent(DragEvent.ACTION_DROP, x, y,
mData, targetInterceptsGlobalDrag(touchedWin),
@@ -336,7 +334,7 @@ class DragState {
endDragLocked();
return false;
} finally {
- if (myPid != touchedWin.mSession.mPid) {
+ if (MY_PID != touchedWin.mSession.mPid) {
event.recycle();
}
}
@@ -364,8 +362,8 @@ class DragState {
mDragWindowHandle.token = mClientChannel.getToken();
mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
mDragWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
- mDragWindowHandle.ownerPid = Process.myPid();
- mDragWindowHandle.ownerUid = Process.myUid();
+ mDragWindowHandle.ownerPid = MY_PID;
+ mDragWindowHandle.ownerUid = MY_UID;
mDragWindowHandle.scaleFactor = 1.0f;
// Keep the default behavior of this window to be focusable, which allows the system
@@ -477,7 +475,7 @@ class DragState {
Slog.w(TAG_WM, "Unable to drag-start window " + newWin);
} finally {
// if the callee was local, the dispatch has already recycled the event
- if (Process.myPid() != newWin.mSession.mPid) {
+ if (MY_PID != newWin.mSession.mPid) {
event.recycle();
}
}
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 59be3e05f2c0..39622c1c5aaf 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -23,7 +23,6 @@ import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.os.InputConfig;
-import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.view.InputApplicationHandle;
@@ -72,8 +71,8 @@ class InputConsumerImpl implements IBinder.DeathRecipient {
mWindowHandle.token = mClientChannel.getToken();
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
- mWindowHandle.ownerPid = Process.myPid();
- mWindowHandle.ownerUid = Process.myUid();
+ mWindowHandle.ownerPid = WindowManagerService.MY_PID;
+ mWindowHandle.ownerUid = WindowManagerService.MY_UID;
mWindowHandle.scaleFactor = 1.0f;
mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.TRUSTED_OVERLAY;
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 61c09cd60413..b5eff41d4f62 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -25,7 +25,6 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.InputConfig;
-import android.os.Process;
import android.view.GestureDetector;
import android.view.InputChannel;
import android.view.InputEvent;
@@ -297,8 +296,8 @@ public class Letterbox {
mWindowHandle.token = mToken;
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
- mWindowHandle.ownerPid = Process.myPid();
- mWindowHandle.ownerUid = Process.myUid();
+ mWindowHandle.ownerPid = WindowManagerService.MY_PID;
+ mWindowHandle.ownerUid = WindowManagerService.MY_UID;
mWindowHandle.scaleFactor = 1.0f;
mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.SLIPPERY;
}
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index 2c7540b8bc0a..2d227b66b3ce 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -37,6 +37,11 @@ final class LetterboxConfiguration {
*/
static final float MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO = 1.0f;
+ // Min allowed aspect ratio for unresizable apps which is used when an app doesn't specify
+ // android:minAspectRatio in accordance with the CDD 7.1.1.2 requirement:
+ // https://source.android.com/compatibility/12/android-12-cdd#7112_screen_aspect_ratio
+ static final float MIN_UNRESIZABLE_ASPECT_RATIO = 4 / 3f;
+
/** Enum for Letterbox background type. */
@Retention(RetentionPolicy.SOURCE)
@IntDef({LETTERBOX_BACKGROUND_SOLID_COLOR, LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND,
@@ -104,6 +109,11 @@ final class LetterboxConfiguration {
// MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO will be ignored.
private float mFixedOrientationLetterboxAspectRatio;
+ // Default min aspect ratio for unresizable apps which is used when an app doesn't specify
+ // android:minAspectRatio in accordance with the CDD 7.1.1.2 requirement:
+ // https://source.android.com/compatibility/12/android-12-cdd#7112_screen_aspect_ratio
+ private float mDefaultMinAspectRatioForUnresizableApps;
+
// Corners radius for activities presented in the letterbox mode, values < 0 will be ignored.
private int mLetterboxActivityCornersRadius;
@@ -177,6 +187,9 @@ final class LetterboxConfiguration {
// Whether education is allowed for letterboxed fullscreen apps.
private boolean mIsEducationEnabled;
+ // Whether using split screen aspect ratio as a default aspect ratio for unresizable apps.
+ private boolean mIsSplitScreenAspectRatioForUnresizableAppsEnabled;
+
LetterboxConfiguration(Context systemUiContext) {
mContext = systemUiContext;
mFixedOrientationLetterboxAspectRatio = mContext.getResources().getFloat(
@@ -204,6 +217,10 @@ final class LetterboxConfiguration {
mLetterboxPositionForVerticalReachability = mDefaultPositionForVerticalReachability;
mIsEducationEnabled = mContext.getResources().getBoolean(
R.bool.config_letterboxIsEducationEnabled);
+ setDefaultMinAspectRatioForUnresizableApps(mContext.getResources().getFloat(
+ R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps));
+ mIsSplitScreenAspectRatioForUnresizableAppsEnabled = mContext.getResources().getBoolean(
+ R.bool.config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled);
}
/**
@@ -233,6 +250,43 @@ final class LetterboxConfiguration {
}
/**
+ * Resets the min aspect ratio for unresizable apps which is used when an app doesn't specify
+ * {@code android:minAspectRatio} to {@link
+ * R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps}.
+ *
+ * @throws AssertionError if {@link
+ * R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps} is < {@link
+ * #MIN_UNRESIZABLE_ASPECT_RATIO}.
+ */
+ void resetDefaultMinAspectRatioForUnresizableApps() {
+ setDefaultMinAspectRatioForUnresizableApps(mContext.getResources().getFloat(
+ R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps));
+ }
+
+ /**
+ * Gets the min aspect ratio for unresizable apps which is used when an app doesn't specify
+ * {@code android:minAspectRatio}.
+ */
+ float getDefaultMinAspectRatioForUnresizableApps() {
+ return mDefaultMinAspectRatioForUnresizableApps;
+ }
+
+ /**
+ * Overrides the min aspect ratio for unresizable apps which is used when an app doesn't
+ * specify {@code android:minAspectRatio}.
+ *
+ * @throws AssertionError if given value is < {@link #MIN_UNRESIZABLE_ASPECT_RATIO}.
+ */
+ void setDefaultMinAspectRatioForUnresizableApps(float aspectRatio) {
+ if (aspectRatio < MIN_UNRESIZABLE_ASPECT_RATIO) {
+ throw new AssertionError(
+ "Unexpected min aspect ratio for unresizable apps, it should be <= "
+ + MIN_UNRESIZABLE_ASPECT_RATIO + " but was " + aspectRatio);
+ }
+ mDefaultMinAspectRatioForUnresizableApps = aspectRatio;
+ }
+
+ /**
* Overrides corners raidus for activities presented in the letterbox mode. If given value < 0,
* both it and a value of {@link
* com.android.internal.R.integer.config_letterboxActivityCornersRadius} will be ignored and
@@ -748,4 +802,28 @@ final class LetterboxConfiguration {
R.bool.config_letterboxIsEducationEnabled);
}
+ /**
+ * Whether using split screen aspect ratio as a default aspect ratio for unresizable apps.
+ */
+ boolean getIsSplitScreenAspectRatioForUnresizableAppsEnabled() {
+ return mIsSplitScreenAspectRatioForUnresizableAppsEnabled;
+ }
+
+ /**
+ * Overrides whether using split screen aspect ratio as a default aspect ratio for unresizable
+ * apps.
+ */
+ void setIsSplitScreenAspectRatioForUnresizableAppsEnabled(boolean enabled) {
+ mIsSplitScreenAspectRatioForUnresizableAppsEnabled = enabled;
+ }
+
+ /**
+ * Resets whether using split screen aspect ratio as a default aspect ratio for unresizable
+ * apps {@link R.bool.config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled}.
+ */
+ void resetIsSplitScreenAspectRatioForUnresizableAppsEnabled() {
+ mIsSplitScreenAspectRatioForUnresizableAppsEnabled = mContext.getResources().getBoolean(
+ R.bool.config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled);
+ }
+
}
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 201520677b26..df9a87ea1ab0 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -211,12 +211,10 @@ final class LetterboxUiController {
: mLetterboxConfiguration.getLetterboxVerticalPositionMultiplier();
}
- float getFixedOrientationLetterboxAspectRatio(Configuration parentConfiguration) {
- // Don't check resolved windowing mode because it may not be updated yet during
- // configuration change.
- if (!isHorizontalReachabilityEnabled(parentConfiguration)
- && !isVerticalReachabilityEnabled(parentConfiguration)) {
- return mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
+ float getDefaultMinAspectRatioForUnresizableApps() {
+ if (!mLetterboxConfiguration.getIsSplitScreenAspectRatioForUnresizableAppsEnabled()
+ || mActivityRecord.getDisplayContent() == null) {
+ return mLetterboxConfiguration.getDefaultMinAspectRatioForUnresizableApps();
}
int dividerWindowWidth =
@@ -226,10 +224,14 @@ final class LetterboxUiController {
int dividerSize = dividerWindowWidth - dividerInsets * 2;
// Getting the same aspect ratio that apps get in split screen.
- Rect bounds = new Rect(parentConfiguration.windowConfiguration.getAppBounds());
- bounds.inset(dividerSize, /* dy */ 0);
- bounds.right = bounds.centerX();
-
+ Rect bounds = new Rect(mActivityRecord.getDisplayContent().getBounds());
+ if (bounds.width() >= bounds.height()) {
+ bounds.inset(/* dx */ dividerSize, /* dy */ 0);
+ bounds.right = bounds.centerX();
+ } else {
+ bounds.inset(/* dx */ 0, /* dy */ dividerSize);
+ bounds.bottom = bounds.centerY();
+ }
return computeAspectRatio(bounds);
}
@@ -538,8 +540,11 @@ final class LetterboxUiController {
pw.println(prefix + " letterboxVerticalPositionMultiplier="
+ getVerticalPositionMultiplier(mActivityRecord.getParent().getConfiguration()));
pw.println(prefix + " fixedOrientationLetterboxAspectRatio="
- + getFixedOrientationLetterboxAspectRatio(
- mActivityRecord.getParent().getConfiguration()));
+ + mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio());
+ pw.println(prefix + " defaultMinAspectRatioForUnresizableApps="
+ + mLetterboxConfiguration.getDefaultMinAspectRatioForUnresizableApps());
+ pw.println(prefix + " isSplitScreenAspectRatioForUnresizableAppsEnabled="
+ + mLetterboxConfiguration.getIsSplitScreenAspectRatioForUnresizableAppsEnabled());
}
/**
@@ -556,6 +561,9 @@ final class LetterboxUiController {
if (mainWin.isLetterboxedForDisplayCutout()) {
return "DISPLAY_CUTOUT";
}
+ if (mActivityRecord.isAspectRatioApplied()) {
+ return "ASPECT_RATIO";
+ }
return "UNKNOWN_REASON";
}
diff --git a/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java b/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
index 0ae119a2191a..2e5474e5e415 100644
--- a/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
+++ b/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
@@ -16,7 +16,7 @@
package com.android.server.wm;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_TOKEN_TRANSFORM;
import android.annotation.NonNull;
import android.view.SurfaceControl;
@@ -83,7 +83,7 @@ public class NavBarFadeAnimationController extends FadeAnimationController{
final AsyncRotationController controller =
mDisplayContent.getAsyncRotationController();
final Runnable fadeAnim = () -> fadeWindowToken(show, mNavigationBar.mToken,
- ANIMATION_TYPE_APP_TRANSITION);
+ ANIMATION_TYPE_TOKEN_TRANSFORM);
if (controller == null) {
fadeAnim.run();
} else if (!controller.isTargetToken(mNavigationBar.mToken)) {
diff --git a/services/core/java/com/android/server/wm/PinnedTaskController.java b/services/core/java/com/android/server/wm/PinnedTaskController.java
index 1ddeee9f46d9..4378b4f17b5b 100644
--- a/services/core/java/com/android/server/wm/PinnedTaskController.java
+++ b/services/core/java/com/android/server/wm/PinnedTaskController.java
@@ -172,7 +172,7 @@ class PinnedTaskController {
*/
void deferOrientationChangeForEnteringPipFromFullScreenIfNeeded() {
final ActivityRecord topFullscreen = mDisplayContent.getActivity(
- a -> a.fillsParent() && !a.getTask().inMultiWindowMode());
+ a -> a.providesOrientation() && !a.getTask().inMultiWindowMode());
if (topFullscreen == null || topFullscreen.hasFixedRotationTransform()) {
return;
}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index e259238c2879..4860762a5f7f 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1390,6 +1390,13 @@ class RecentTasks {
return false;
}
+ // Ignore the task if it is started on a display which is not allow to show its tasks on
+ // Recents.
+ if (task.getDisplayContent() != null
+ && !task.getDisplayContent().canShowTasksInRecents()) {
+ return false;
+ }
+
return true;
}
@@ -1399,13 +1406,19 @@ class RecentTasks {
private boolean isInVisibleRange(Task task, int taskIndex, int numVisibleTasks,
boolean skipExcludedCheck) {
if (!skipExcludedCheck) {
- // Keep the most recent task even if it is excluded from recents
+ // Keep the most recent task of home display even if it is excluded from recents.
final boolean isExcludeFromRecents =
(task.getBaseIntent().getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
== FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
if (isExcludeFromRecents) {
- if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\texcludeFromRecents=true");
- return taskIndex == 0;
+ if (DEBUG_RECENTS_TRIM_TASKS) {
+ Slog.d(TAG,
+ "\texcludeFromRecents=true, taskIndex = " + taskIndex
+ + ", isOnHomeDisplay: " + task.isOnHomeDisplay());
+ }
+ // The Recents is only supported on default display now, we should only keep the
+ // most recent task of home display.
+ return (task.isOnHomeDisplay() && taskIndex == 0);
}
}
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index fd05f19f54c5..baa31a073dd2 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -173,7 +173,7 @@ public class SafeActivityOptions {
if (adapter == null) {
return;
}
- if (callingPid == Process.myPid()) {
+ if (callingPid == WindowManagerService.MY_PID) {
Slog.wtf(TAG, "Safe activity options constructed after clearing calling id");
return;
}
diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java
index ccd018faf075..68dbb0607ac1 100644
--- a/services/core/java/com/android/server/wm/StartingSurfaceController.java
+++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java
@@ -159,9 +159,7 @@ public class StartingSurfaceController {
return null;
}
if (topFullscreenActivity.getWindowConfiguration().getRotation()
- != taskSnapshot.getRotation()
- // Use normal rotation to avoid flickering of IME window in old orientation.
- && !taskSnapshot.hasImeSurface()) {
+ != taskSnapshot.getRotation()) {
// The snapshot should have been checked by ActivityRecord#isSnapshotCompatible
// that the activity will be updated to the same rotation as the snapshot. Since
// the transition is not started yet, fixed rotation transform needs to be applied
@@ -223,6 +221,11 @@ public class StartingSurfaceController {
// Attempt to add starting window from the top-most activity.
for (int i = mDeferringAddStartActivities.size() - 1; i >= 0; --i) {
final DeferringStartingWindowRecord next = mDeferringAddStartActivities.get(i);
+ if (next.mDeferring.getTask() == null) {
+ Slog.e(TAG, "No task exists: " + next.mDeferring.shortComponentName
+ + " parent: " + next.mDeferring.getParent());
+ continue;
+ }
next.mDeferring.showStartingWindow(next.mPrev, mInitNewTask, mInitTaskSwitch,
mInitProcessRunning, true /* startActivity */, next.mSource, topOptions);
// If one succeeds, it is done.
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 3dde2f1aa01f..ca86db9e4f7c 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -553,10 +553,10 @@ class SurfaceAnimator {
public static final int ANIMATION_TYPE_INSETS_CONTROL = 1 << 5;
/**
- * Animation when a fixed rotation transform is applied to a window token.
+ * Animation applied to a non-app window token, e.g. a fixed rotation transform.
* @hide
*/
- public static final int ANIMATION_TYPE_FIXED_TRANSFORM = 1 << 6;
+ public static final int ANIMATION_TYPE_TOKEN_TRANSFORM = 1 << 6;
/**
* Animation when a reveal starting window animation is applied to app window.
@@ -582,7 +582,7 @@ class SurfaceAnimator {
ANIMATION_TYPE_RECENTS,
ANIMATION_TYPE_WINDOW_ANIMATION,
ANIMATION_TYPE_INSETS_CONTROL,
- ANIMATION_TYPE_FIXED_TRANSFORM,
+ ANIMATION_TYPE_TOKEN_TRANSFORM,
ANIMATION_TYPE_STARTING_REVEAL
})
@Retention(RetentionPolicy.SOURCE)
@@ -600,7 +600,7 @@ class SurfaceAnimator {
case ANIMATION_TYPE_RECENTS: return "recents_animation";
case ANIMATION_TYPE_WINDOW_ANIMATION: return "window_animation";
case ANIMATION_TYPE_INSETS_CONTROL: return "insets_animation";
- case ANIMATION_TYPE_FIXED_TRANSFORM: return "fixed_rotation";
+ case ANIMATION_TYPE_TOKEN_TRANSFORM: return "token_transform";
case ANIMATION_TYPE_STARTING_REVEAL: return "starting_reveal";
default: return "unknown type:" + type;
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index b7398786fbc3..7c1488b71bf5 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -1633,7 +1633,7 @@ class Task extends TaskFragment {
* activities on top of it and return the instance.
*
* @param newR Description of the new activity being started.
- * @return Returns the old activity that should be continued to be used,
+ * @return Returns the existing activity in the task that performs the clear-top operation,
* or {@code null} if none was found.
*/
private ActivityRecord clearTopActivities(ActivityRecord newR, int launchFlags) {
@@ -1652,7 +1652,6 @@ class Task extends TaskFragment {
&& !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
if (!r.finishing) {
r.finishIfPossible("clear-task-top", false /* oomAdj */);
- return null;
}
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 42a13a8a8604..d77e9b397ef9 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -152,6 +152,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
final RootWindowContainer mRootWindowContainer;
private final TaskFragmentOrganizerController mTaskFragmentOrganizerController;
+ // TODO(b/233177466): Move mMinWidth and mMinHeight to Task and remove usages in TaskFragment
/**
* Minimal width of this task fragment when it's resizeable. {@link #INVALID_MIN_SIZE} means it
* should use the default minimal width.
@@ -524,6 +525,25 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|| isAllowedToEmbedActivityInTrustedMode(a, uid);
}
+ boolean smallerThanMinDimension(@NonNull ActivityRecord activity) {
+ final Rect taskFragBounds = getBounds();
+ final Task task = getTask();
+ // Don't need to check if the bounds match parent Task bounds because the fallback mechanism
+ // is to reparent the Activity to parent if minimum dimensions are not satisfied.
+ if (task == null || taskFragBounds.equals(task.getBounds())) {
+ return false;
+ }
+ final Point minDimensions = activity.getMinDimensions();
+ if (minDimensions == null) {
+ return false;
+ }
+ final int minWidth = minDimensions.x;
+ final int minHeight = minDimensions.y;
+ final boolean smaller = taskFragBounds.width() < minWidth
+ || taskFragBounds.height() < minHeight;
+ return smaller;
+ }
+
/**
* Checks if the organized task fragment is allowed to embed activity in untrusted mode.
*/
@@ -1561,8 +1581,11 @@ class TaskFragment extends WindowContainer<WindowContainer> {
} else {
prev.schedulePauseTimeout();
- // Unset readiness since we now need to wait until this pause is complete.
- mTransitionController.setReady(this, false /* ready */);
+ // All activities will be stopped when sleeping, don't need to wait for pause.
+ if (!uiSleeping) {
+ // Unset readiness since we now need to wait until this pause is complete.
+ mTransitionController.setReady(this, false /* ready */);
+ }
return true;
}
@@ -1744,7 +1767,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
mClearedTaskForReuse = false;
mClearedTaskFragmentForPip = false;
- boolean isAddingActivity = child.asActivityRecord() != null;
+ final ActivityRecord addingActivity = child.asActivityRecord();
+ final boolean isAddingActivity = addingActivity != null;
final Task task = isAddingActivity ? getTask() : null;
// If this task had any activity before we added this one.
@@ -1769,7 +1793,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
mBackScreenshots.put(r.mActivityComponent.flattenToString(), backBuffer);
}
child.asActivityRecord().inHistory = true;
- task.onDescendantActivityAdded(taskHadActivity, activityType, child.asActivityRecord());
+ task.onDescendantActivityAdded(taskHadActivity, activityType, addingActivity);
}
}
@@ -2053,9 +2077,15 @@ class TaskFragment extends WindowContainer<WindowContainer> {
final boolean inPipTransition = windowingMode == WINDOWING_MODE_PINNED
&& !mTmpFullBounds.isEmpty() && mTmpFullBounds.equals(parentBounds);
if (WindowConfiguration.isFloating(windowingMode) && !inPipTransition) {
- // For floating tasks, calculate the smallest width from the bounds of the task
+ // For floating tasks, calculate the smallest width from the bounds of the
+ // task, because they should not be affected by insets.
inOutConfig.smallestScreenWidthDp = (int) (0.5f
+ Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
+ } else if (isEmbedded()) {
+ // For embedded TFs, the smallest width should be updated. Otherwise, inherit
+ // from the parent task would result in applications loaded wrong resource.
+ inOutConfig.smallestScreenWidthDp =
+ Math.min(inOutConfig.screenWidthDp, inOutConfig.screenHeightDp);
}
// otherwise, it will just inherit
}
@@ -2278,7 +2308,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
TaskFragmentInfo getTaskFragmentInfo() {
List<IBinder> childActivities = new ArrayList<>();
for (int i = 0; i < getChildCount(); i++) {
- final WindowContainer wc = getChildAt(i);
+ final WindowContainer<?> wc = getChildAt(i);
final ActivityRecord ar = wc.asActivityRecord();
if (mTaskFragmentOrganizerUid != INVALID_UID && ar != null
&& ar.info.processName.equals(mTaskFragmentOrganizerProcessName)
@@ -2298,7 +2328,31 @@ class TaskFragment extends WindowContainer<WindowContainer> {
childActivities,
positionInParent,
mClearedTaskForReuse,
- mClearedTaskFragmentForPip);
+ mClearedTaskFragmentForPip,
+ calculateMinDimension());
+ }
+
+ /**
+ * Calculates the minimum dimensions that this TaskFragment can be resized.
+ * @see TaskFragmentInfo#getMinimumWidth()
+ * @see TaskFragmentInfo#getMinimumHeight()
+ */
+ Point calculateMinDimension() {
+ final int[] maxMinWidth = new int[1];
+ final int[] maxMinHeight = new int[1];
+
+ forAllActivities(a -> {
+ if (a.finishing) {
+ return;
+ }
+ final Point minDimensions = a.getMinDimensions();
+ if (minDimensions == null) {
+ return;
+ }
+ maxMinWidth[0] = Math.max(maxMinWidth[0], minDimensions.x);
+ maxMinHeight[0] = Math.max(maxMinHeight[0], minDimensions.y);
+ });
+ return new Point(maxMinWidth[0], maxMinHeight[0]);
}
@Nullable
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 47c397d12720..03ca4fd49a96 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -41,7 +41,6 @@ import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.os.InputConfig;
-import android.os.Process;
import android.os.RemoteException;
import android.os.Trace;
import android.util.DisplayMetrics;
@@ -222,8 +221,8 @@ class TaskPositioner implements IBinder.DeathRecipient {
mDragWindowHandle.token = mClientChannel.getToken();
mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
mDragWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
- mDragWindowHandle.ownerPid = Process.myPid();
- mDragWindowHandle.ownerUid = Process.myUid();
+ mDragWindowHandle.ownerPid = WindowManagerService.MY_PID;
+ mDragWindowHandle.ownerUid = WindowManagerService.MY_UID;
mDragWindowHandle.scaleFactor = 1.0f;
// When dragging the window around, we do not want to steal focus for the window.
mDragWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE;
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 4e8b9db75dda..84f6104652e3 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -95,6 +95,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.function.Predicate;
/**
@@ -131,18 +132,27 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
*/
private static final int STATE_ABORT = 3;
+ /**
+ * This transition has finished playing successfully.
+ */
+ private static final int STATE_FINISHED = 4;
+
@IntDef(prefix = { "STATE_" }, value = {
STATE_PENDING,
STATE_COLLECTING,
STATE_STARTED,
STATE_PLAYING,
- STATE_ABORT
+ STATE_ABORT,
+ STATE_FINISHED
})
@Retention(RetentionPolicy.SOURCE)
@interface TransitionState {}
final @TransitionType int mType;
private int mSyncId = -1;
+ // Used for tracking a Transition throughout a lifecycle (i.e. from STATE_COLLECTING to
+ // STATE_FINISHED or STATE_ABORT), and should only be used for testing and debugging.
+ private int mDebugId = -1;
private @TransitionFlags int mFlags;
private final TransitionController mController;
private final BLASTSyncEngine mSyncEngine;
@@ -202,6 +212,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
mFlags = flags;
mController = controller;
mSyncEngine = syncEngine;
+
+ controller.mTransitionTracer.logState(this);
}
void addFlag(int flag) {
@@ -214,10 +226,26 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
mTransientLaunches = new ArrayMap<>();
}
mTransientLaunches.put(activity, restoreBelow);
+ setTransientLaunchToChanges(activity);
+
+ if (restoreBelow != null) {
+ final ChangeInfo info = mChanges.get(restoreBelow);
+ info.mFlags |= ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH;
+ }
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Transition %d: Set %s as "
+ "transient-launch", mSyncId, activity);
}
+ boolean isTransientHide(@NonNull Task task) {
+ if (mTransientLaunches == null) return false;
+ for (int i = 0; i < mTransientLaunches.size(); ++i) {
+ if (mTransientLaunches.valueAt(i) == task) {
+ return true;
+ }
+ }
+ return false;
+ }
+
boolean isTransientLaunch(@NonNull ActivityRecord activity) {
return mTransientLaunches != null && mTransientLaunches.containsKey(activity);
}
@@ -242,11 +270,35 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
info.mFlags = info.mFlags | ChangeInfo.FLAG_SEAMLESS_ROTATION;
}
+ /**
+ * Only set flag to the parent tasks and activity itself.
+ */
+ private void setTransientLaunchToChanges(@NonNull WindowContainer wc) {
+ for (WindowContainer curr = wc; curr != null && mChanges.containsKey(curr);
+ curr = curr.getParent()) {
+ if (curr.asTask() == null && curr.asActivityRecord() == null) {
+ return;
+ }
+ final ChangeInfo info = mChanges.get(curr);
+ info.mFlags = info.mFlags | ChangeInfo.FLAG_TRANSIENT_LAUNCH;
+ }
+ }
+
+ @TransitionState
+ int getState() {
+ return mState;
+ }
+
@VisibleForTesting
int getSyncId() {
return mSyncId;
}
+ @VisibleForTesting
+ int getDebugId() {
+ return mDebugId;
+ }
+
@TransitionFlags
int getFlags() {
return mFlags;
@@ -259,6 +311,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
}
mState = STATE_COLLECTING;
mSyncId = mSyncEngine.startSyncSet(this, timeoutMs, TAG);
+ mDebugId = mSyncId;
+
+ mController.mTransitionTracer.logState(this);
}
/**
@@ -276,6 +331,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Starting Transition %d",
mSyncId);
applyReady();
+
+ mController.mTransitionTracer.logState(this);
}
/**
@@ -644,6 +701,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
dc.removeImeSurfaceImmediately();
dc.handleCompleteDeferredRemoval();
}
+
+ mState = STATE_FINISHED;
+ mController.mTransitionTracer.logState(this);
}
void abort() {
@@ -1546,10 +1606,14 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
* seamless rotation. This is currently only used by DisplayContent during fixed-rotation.
*/
private static final int FLAG_SEAMLESS_ROTATION = 1;
+ private static final int FLAG_TRANSIENT_LAUNCH = 2;
+ private static final int FLAG_ABOVE_TRANSIENT_LAUNCH = 4;
@IntDef(prefix = { "FLAG_" }, value = {
FLAG_NONE,
- FLAG_SEAMLESS_ROTATION
+ FLAG_SEAMLESS_ROTATION,
+ FLAG_TRANSIENT_LAUNCH,
+ FLAG_ABOVE_TRANSIENT_LAUNCH
})
@Retention(RetentionPolicy.SOURCE)
@interface Flag {}
@@ -1586,6 +1650,11 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
}
boolean hasChanged(@NonNull WindowContainer newState) {
+ // the task including transient launch must promote to root task
+ if ((mFlags & ChangeInfo.FLAG_TRANSIENT_LAUNCH) != 0
+ || (mFlags & ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH) != 0) {
+ return true;
+ }
// If it's invisible and hasn't changed visibility, always return false since even if
// something changed, it wouldn't be a visible change.
final boolean currVisible = newState.isVisibleRequested();
@@ -1601,6 +1670,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
@TransitionInfo.TransitionMode
int getTransitMode(@NonNull WindowContainer wc) {
+ if ((mFlags & ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH) != 0) {
+ return TRANSIT_CLOSE;
+ }
final boolean nowVisible = wc.isVisibleRequested();
if (nowVisible == mVisible) {
return TRANSIT_CHANGE;
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 85101660b051..6d31e937984e 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -75,6 +75,7 @@ class TransitionController {
private ITransitionPlayer mTransitionPlayer;
final TransitionMetricsReporter mTransitionMetricsReporter = new TransitionMetricsReporter();
+ final TransitionTracer mTransitionTracer;
private IApplicationThread mTransitionPlayerThread;
final ActivityTaskManagerService mAtm;
@@ -100,10 +101,12 @@ class TransitionController {
final StatusBarManagerInternal mStatusBar;
TransitionController(ActivityTaskManagerService atm,
- TaskSnapshotController taskSnapshotController) {
+ TaskSnapshotController taskSnapshotController,
+ TransitionTracer transitionTracer) {
mAtm = atm;
mStatusBar = LocalServices.getService(StatusBarManagerInternal.class);
mTaskSnapshotController = taskSnapshotController;
+ mTransitionTracer = transitionTracer;
mTransitionPlayerDeath = () -> {
synchronized (mAtm.mGlobalLock) {
// Clean-up/finish any playing transitions.
@@ -282,6 +285,16 @@ class TransitionController {
return false;
}
+ boolean isTransientHide(@NonNull Task task) {
+ if (mCollectingTransition != null && mCollectingTransition.isTransientHide(task)) {
+ return true;
+ }
+ for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
+ if (mPlayingTransitions.get(i).isTransientHide(task)) return true;
+ }
+ return false;
+ }
+
/**
* @return {@code true} if {@param ar} is part of a transient-launch activity in an active
* transition.
@@ -514,6 +527,7 @@ class TransitionController {
setAnimationRunning(true /* running */);
}
mPlayingTransitions.add(transition);
+ mTransitionTracer.logState(transition);
}
private void setAnimationRunning(boolean running) {
@@ -532,6 +546,7 @@ class TransitionController {
}
transition.abort();
mCollectingTransition = null;
+ mTransitionTracer.logState(transition);
}
/**
diff --git a/services/core/java/com/android/server/wm/TransitionTracer.java b/services/core/java/com/android/server/wm/TransitionTracer.java
new file mode 100644
index 000000000000..192b9abc62a7
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TransitionTracer.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.os.Build.IS_USER;
+
+import static com.android.server.wm.shell.ChangeInfo.CHANGE_FLAGS;
+import static com.android.server.wm.shell.ChangeInfo.HAS_CHANGED;
+import static com.android.server.wm.shell.ChangeInfo.TRANSIT_MODE;
+import static com.android.server.wm.shell.ChangeInfo.WINDOW_IDENTIFIER;
+import static com.android.server.wm.shell.Transition.CHANGE;
+import static com.android.server.wm.shell.Transition.FLAGS;
+import static com.android.server.wm.shell.Transition.ID;
+import static com.android.server.wm.shell.Transition.STATE;
+import static com.android.server.wm.shell.Transition.TIMESTAMP;
+import static com.android.server.wm.shell.Transition.TRANSITION_TYPE;
+import static com.android.server.wm.shell.TransitionTraceProto.MAGIC_NUMBER;
+import static com.android.server.wm.shell.TransitionTraceProto.MAGIC_NUMBER_H;
+import static com.android.server.wm.shell.TransitionTraceProto.MAGIC_NUMBER_L;
+import static com.android.server.wm.shell.TransitionTraceProto.TRANSITION;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.util.Log;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.util.TraceBuffer;
+import com.android.server.wm.Transition.ChangeInfo;
+import com.android.server.wm.shell.TransitionTraceProto;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * Helper class to collect and dump transition traces.
+ */
+public class TransitionTracer {
+
+ private static final String LOG_TAG = "TransitionTracer";
+
+ /**
+ * Maximum buffer size, currently defined as 5 MB
+ */
+ private static final int BUFFER_CAPACITY = 5120 * 1024; // 5 MB
+ static final String WINSCOPE_EXT = ".winscope";
+ private static final String TRACE_FILE = "/data/misc/wmtrace/transition_trace" + WINSCOPE_EXT;
+ private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+
+ private final TransitionTraceBuffer mTraceBuffer = new TransitionTraceBuffer();
+
+ private final Object mEnabledLock = new Object();
+ private volatile boolean mEnabled = false;
+
+ private long mTraceStartTimestamp;
+
+ private class TransitionTraceBuffer {
+ private final TraceBuffer mBuffer = new TraceBuffer(BUFFER_CAPACITY);
+
+ private void pushTransitionState(Transition transition) {
+ final ProtoOutputStream outputStream = new ProtoOutputStream();
+ final long transitionEntryToken = outputStream.start(TRANSITION);
+
+ outputStream.write(ID, transition.getDebugId());
+ outputStream.write(TIMESTAMP, SystemClock.elapsedRealtimeNanos());
+ outputStream.write(TRANSITION_TYPE, transition.mType);
+ outputStream.write(STATE, transition.getState());
+ outputStream.write(FLAGS, transition.getFlags());
+
+ for (int i = 0; i < transition.mChanges.size(); ++i) {
+ final WindowContainer window = transition.mChanges.keyAt(i);
+ final ChangeInfo changeInfo = transition.mChanges.valueAt(i);
+ writeChange(outputStream, window, changeInfo);
+ }
+
+ outputStream.end(transitionEntryToken);
+
+ mBuffer.add(outputStream);
+ }
+
+ private void writeChange(ProtoOutputStream outputStream, WindowContainer window,
+ ChangeInfo changeInfo) {
+ Trace.beginSection("TransitionProto#addChange");
+ final long changeEntryToken = outputStream.start(CHANGE);
+
+ final int transitMode = changeInfo.getTransitMode(window);
+ final boolean hasChanged = changeInfo.hasChanged(window);
+ final int changeFlags = changeInfo.getChangeFlags(window);
+
+ outputStream.write(TRANSIT_MODE, transitMode);
+ outputStream.write(HAS_CHANGED, hasChanged);
+ outputStream.write(CHANGE_FLAGS, changeFlags);
+ window.writeIdentifierToProto(outputStream, WINDOW_IDENTIFIER);
+
+ outputStream.end(changeEntryToken);
+ Trace.endSection();
+ }
+
+ public void writeToFile(File file, ProtoOutputStream proto) throws IOException {
+ mBuffer.writeTraceToFile(file, proto);
+ }
+
+ public void reset() {
+ mBuffer.resetBuffer();
+ }
+ }
+
+ /**
+ * Records the current state of a transition in the transition trace (if it is running).
+ * @param transition the transition that we want to record the state of.
+ */
+ public void logState(com.android.server.wm.Transition transition) {
+ if (!mEnabled) {
+ return;
+ }
+
+ Log.d(LOG_TAG, "Logging state of transition " + transition);
+ mTraceBuffer.pushTransitionState(transition);
+ }
+
+ /**
+ * Starts collecting transitions for the trace.
+ * If called while a trace is already running, this will reset the trace.
+ */
+ public void startTrace(@Nullable PrintWriter pw) {
+ if (IS_USER) {
+ LogAndPrintln.e(pw, "Tracing is not supported on user builds.");
+ return;
+ }
+ Trace.beginSection("TransitionTracer#startTrace");
+ LogAndPrintln.i(pw, "Starting shell transition trace.");
+ synchronized (mEnabledLock) {
+ mTraceStartTimestamp = SystemClock.elapsedRealtime();
+ mEnabled = true;
+ mTraceBuffer.reset();
+ }
+ Trace.endSection();
+ }
+
+ /**
+ * Stops collecting the transition trace and dump to trace to file.
+ *
+ * Dumps the trace to @link{TRACE_FILE}.
+ */
+ public void stopTrace(@Nullable PrintWriter pw) {
+ stopTrace(pw, new File(TRACE_FILE));
+ }
+
+ /**
+ * Stops collecting the transition trace and dump to trace to file.
+ * @param outputFile The file to dump the transition trace to.
+ */
+ public void stopTrace(@Nullable PrintWriter pw, File outputFile) {
+ if (IS_USER) {
+ LogAndPrintln.e(pw, "Tracing is not supported on user builds.");
+ return;
+ }
+ Trace.beginSection("TransitionTracer#stopTrace");
+ LogAndPrintln.i(pw, "Stopping shell transition trace.");
+ synchronized (mEnabledLock) {
+ if (!mEnabled) {
+ LogAndPrintln.e(pw,
+ "Error: Tracing can't be stopped because it hasn't been started.");
+ return;
+ }
+
+ mEnabled = false;
+ writeTraceToFileLocked(pw, outputFile);
+ }
+ Trace.endSection();
+ }
+
+ boolean isEnabled() {
+ return mEnabled;
+ }
+
+ private void writeTraceToFileLocked(@Nullable PrintWriter pw, File file) {
+ Trace.beginSection("TransitionTracer#writeTraceToFileLocked");
+ try {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+ proto.write(TransitionTraceProto.TIMESTAMP, mTraceStartTimestamp);
+ int pid = android.os.Process.myPid();
+ LogAndPrintln.i(pw, "Writing file to " + file.getAbsolutePath()
+ + " from process " + pid);
+ mTraceBuffer.writeToFile(file, proto);
+ } catch (IOException e) {
+ LogAndPrintln.e(pw, "Unable to write buffer to file", e);
+ }
+ Trace.endSection();
+ }
+
+ private static class LogAndPrintln {
+ private static void i(@Nullable PrintWriter pw, String msg) {
+ Log.i(LOG_TAG, msg);
+ if (pw != null) {
+ pw.println(msg);
+ pw.flush();
+ }
+ }
+
+ private static void e(@Nullable PrintWriter pw, String msg) {
+ Log.e(LOG_TAG, msg);
+ if (pw != null) {
+ pw.println("ERROR: " + msg);
+ pw.flush();
+ }
+ }
+
+ private static void e(@Nullable PrintWriter pw, String msg, @NonNull Exception e) {
+ Log.e(LOG_TAG, msg, e);
+ if (pw != null) {
+ pw.println("ERROR: " + msg + " ::\n " + e);
+ pw.flush();
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index a32a6087a04d..6245005606d7 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -21,6 +21,7 @@ import static android.app.WallpaperManager.COMMAND_UNFREEZE;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
@@ -181,15 +182,11 @@ class WallpaperController {
mFindResults.setUseTopWallpaperAsTarget(true);
}
- final RecentsAnimationController recentsAnimationController =
- mService.getRecentsAnimationController();
final boolean animationWallpaper = animatingContainer != null
&& animatingContainer.getAnimation() != null
&& animatingContainer.getAnimation().getShowWallpaper();
final boolean hasWallpaper = w.hasWallpaper() || animationWallpaper;
- final boolean isRecentsTransitionTarget = (recentsAnimationController != null
- && recentsAnimationController.isWallpaperVisible(w));
- if (isRecentsTransitionTarget) {
+ if (isRecentsTransitionTarget(w)) {
if (DEBUG_WALLPAPER) Slog.v(TAG, "Found recents animation wallpaper target: " + w);
mFindResults.setWallpaperTarget(w);
return true;
@@ -213,6 +210,22 @@ class WallpaperController {
return false;
};
+ private boolean isRecentsTransitionTarget(WindowState w) {
+ if (w.mTransitionController.isShellTransitionsEnabled()) {
+ // Because the recents activity is invisible in background while keyguard is occluded
+ // (the activity window is on screen while keyguard is locked) with recents animation,
+ // the task animating by recents needs to be wallpaper target to make wallpaper visible.
+ // While for unlocked case, because recents activity will be moved to top, it can be
+ // the wallpaper target naturally.
+ return w.mActivityRecord != null && w.mAttrs.type == TYPE_BASE_APPLICATION
+ && mDisplayContent.isKeyguardLocked()
+ && w.mTransitionController.isTransientHide(w.getTask());
+ }
+ // The window is either the recents activity or is in the task animating by the recents.
+ final RecentsAnimationController controller = mService.getRecentsAnimationController();
+ return controller != null && controller.isWallpaperVisible(w);
+ }
+
/**
* @see #computeLastWallpaperZoomOut()
*/
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index f9d19e22ddc7..d7257180f01b 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1495,8 +1495,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
*/
int getOrientation(int candidate) {
mLastOrientationSource = null;
- if (!fillsParent()) {
- // Ignore containers that don't completely fill their parents.
+ if (!providesOrientation()) {
return SCREEN_ORIENTATION_UNSET;
}
@@ -1530,8 +1529,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
continue;
}
- if (wc.fillsParent() || orientation != SCREEN_ORIENTATION_UNSPECIFIED) {
- // Use the orientation if the container fills its parent or requested an explicit
+ if (wc.providesOrientation() || orientation != SCREEN_ORIENTATION_UNSPECIFIED) {
+ // Use the orientation if the container can provide or requested an explicit
// orientation that isn't SCREEN_ORIENTATION_UNSPECIFIED.
ProtoLog.v(WM_DEBUG_ORIENTATION, "%s is requesting orientation %d (%s)",
wc.toString(), orientation,
@@ -1560,6 +1559,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
return source;
}
+ boolean providesOrientation() {
+ return fillsParent();
+ }
+
/**
* Returns true if this container is opaque and fills all the space made available by its parent
* container.
diff --git a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
index 9b6f4d947694..b000a9841d06 100644
--- a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
+++ b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
@@ -33,7 +33,6 @@ import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.hardware.HardwareBuffer;
-import android.os.Process;
import android.util.proto.ProtoOutputStream;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Builder;
@@ -91,7 +90,7 @@ class WindowContainerThumbnail implements Animatable {
.setBLASTLayer()
.setFormat(PixelFormat.TRANSLUCENT)
.setMetadata(METADATA_WINDOW_TYPE, mWindowContainer.getWindowingMode())
- .setMetadata(METADATA_OWNER_UID, Process.myUid())
+ .setMetadata(METADATA_OWNER_UID, WindowManagerService.MY_UID)
.setCallsite("WindowContainerThumbnail")
.build();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b75234a23861..66fb4c9e5c94 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -397,9 +397,8 @@ public class WindowManagerService extends IWindowManager.Stub
private static final String PROPERTY_EMULATOR_CIRCULAR = "ro.emulator.circular";
- // Used to indicate that if there is already a transition set, it should be preserved when
- // trying to apply a new one.
- private static final boolean ALWAYS_KEEP_CURRENT = true;
+ static final int MY_PID = myPid();
+ static final int MY_UID = myUid();
static final int LOGTAG_INPUT_FOCUS = 62001;
@@ -460,6 +459,7 @@ public class WindowManagerService extends IWindowManager.Stub
final WindowManagerConstants mConstants;
final WindowTracing mWindowTracing;
+ final TransitionTracer mTransitionTracer;
private final DisplayAreaPolicy.Provider mDisplayAreaPolicyProvider;
@@ -1205,8 +1205,7 @@ public class WindowManagerService extends IWindowManager.Stub
com.android.internal.R.bool.config_hasPermanentDpad);
mInTouchMode = context.getResources().getBoolean(
com.android.internal.R.bool.config_defaultInTouchMode);
- inputManager.setInTouchMode(
- mInTouchMode, myPid(), myUid(), /* hasPermission = */ true);
+ inputManager.setInTouchMode(mInTouchMode, MY_PID, MY_UID, true /* hasPermission */);
mDrawLockTimeoutMillis = context.getResources().getInteger(
com.android.internal.R.integer.config_drawLockTimeoutMillis);
mAllowAnimationsInLowPowerMode = context.getResources().getBoolean(
@@ -1247,6 +1246,7 @@ public class WindowManagerService extends IWindowManager.Stub
mWindowTracing = WindowTracing.createDefaultAndStartLooper(this,
Choreographer.getInstance());
+ mTransitionTracer = new TransitionTracer();
LocalServices.addService(WindowManagerPolicy.class, mPolicy);
@@ -2700,7 +2700,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
boolean checkCallingPermission(String permission, String func, boolean printLog) {
- if (Binder.getCallingPid() == myPid()) {
+ if (Binder.getCallingPid() == MY_PID) {
return true;
}
@@ -2860,7 +2860,7 @@ public class WindowManagerService extends IWindowManager.Stub
// registration in DisplayContent#onParentChanged at DisplayContent initialization.
final DisplayContent dc = mRoot.getDisplayContent(displayId);
if (dc == null) {
- if (Binder.getCallingPid() != myPid()) {
+ if (Binder.getCallingPid() != MY_PID) {
throw new WindowManager.InvalidDisplayException("attachToDisplayContent: "
+ "trying to attach to a non-existing display:" + displayId);
}
@@ -5890,6 +5890,21 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
+ public void startTransitionTrace() {
+ mTransitionTracer.startTrace(null /* printwriter */);
+ }
+
+ @Override
+ public void stopTransitionTrace() {
+ mTransitionTracer.stopTrace(null /* printwriter */);
+ }
+
+ @Override
+ public boolean isTransitionTraceEnabled() {
+ return mTransitionTracer.isEnabled();
+ }
+
+ @Override
public boolean registerCrossWindowBlurEnabledListener(
ICrossWindowBlurEnabledListener listener) {
return mBlurController.registerCrossWindowBlurEnabledListener(listener);
@@ -8769,7 +8784,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public boolean getWindowInsets(WindowManager.LayoutParams attrs, int displayId,
InsetsState outInsetsState) {
- final boolean fromLocal = Binder.getCallingPid() == myPid();
+ final boolean fromLocal = Binder.getCallingPid() == MY_PID;
final int uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 8a6a4df0fd42..02f056cd33af 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -149,6 +149,8 @@ public class WindowManagerShellCommand extends ShellCommand {
return runReset(pw);
case "disable-blur":
return runSetBlurDisabled(pw);
+ case "shell":
+ return runWmShellCommand(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -629,6 +631,26 @@ public class WindowManagerShellCommand extends ShellCommand {
return 0;
}
+ private int runSetDefaultMinAspectRatioForUnresizableApps(PrintWriter pw)
+ throws RemoteException {
+ final float aspectRatio;
+ try {
+ String arg = getNextArgRequired();
+ aspectRatio = Float.parseFloat(arg);
+ } catch (NumberFormatException e) {
+ getErrPrintWriter().println("Error: bad aspect ratio format " + e);
+ return -1;
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println(
+ "Error: aspect ratio should be provided as an argument " + e);
+ return -1;
+ }
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setDefaultMinAspectRatioForUnresizableApps(aspectRatio);
+ }
+ return 0;
+ }
+
private int runSetLetterboxActivityCornersRadius(PrintWriter pw) throws RemoteException {
final int cornersRadius;
try {
@@ -929,6 +951,30 @@ public class WindowManagerShellCommand extends ShellCommand {
return 0;
}
+ private int runSetLetterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled(PrintWriter pw)
+ throws RemoteException {
+ String arg = getNextArg();
+ final boolean enabled;
+ switch (arg) {
+ case "true":
+ case "1":
+ enabled = true;
+ break;
+ case "false":
+ case "0":
+ enabled = false;
+ break;
+ default:
+ getErrPrintWriter().println("Error: expected true, 1, false, 0, but got " + arg);
+ return -1;
+ }
+
+ synchronized (mInternal.mGlobalLock) {
+ mLetterboxConfiguration.setIsSplitScreenAspectRatioForUnresizableAppsEnabled(enabled);
+ }
+ return 0;
+ }
+
private int runSetLetterboxStyle(PrintWriter pw) throws RemoteException {
if (peekNextArg() == null) {
getErrPrintWriter().println("Error: No arguments provided.");
@@ -939,6 +985,9 @@ public class WindowManagerShellCommand extends ShellCommand {
case "--aspectRatio":
runSetFixedOrientationLetterboxAspectRatio(pw);
break;
+ case "--minAspectRatioForUnresizable":
+ runSetDefaultMinAspectRatioForUnresizableApps(pw);
+ break;
case "--cornerRadius":
runSetLetterboxActivityCornersRadius(pw);
break;
@@ -978,6 +1027,9 @@ public class WindowManagerShellCommand extends ShellCommand {
case "--isEducationEnabled":
runSetLetterboxIsEducationEnabled(pw);
break;
+ case "--isSplitScreenAspectRatioForUnresizableAppsEnabled":
+ runSetLetterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled(pw);
+ break;
default:
getErrPrintWriter().println(
"Error: Unrecognized letterbox style option: " + arg);
@@ -998,6 +1050,9 @@ public class WindowManagerShellCommand extends ShellCommand {
case "aspectRatio":
mLetterboxConfiguration.resetFixedOrientationLetterboxAspectRatio();
break;
+ case "minAspectRatioForUnresizable":
+ mLetterboxConfiguration.resetDefaultMinAspectRatioForUnresizableApps();
+ break;
case "cornerRadius":
mLetterboxConfiguration.resetLetterboxActivityCornersRadius();
break;
@@ -1034,6 +1089,10 @@ public class WindowManagerShellCommand extends ShellCommand {
case "isEducationEnabled":
mLetterboxConfiguration.getIsEducationEnabled();
break;
+ case "isSplitScreenAspectRatioForUnresizableAppsEnabled":
+ mLetterboxConfiguration
+ .getIsSplitScreenAspectRatioForUnresizableAppsEnabled();
+ break;
default:
getErrPrintWriter().println(
"Error: Unrecognized letterbox style option: " + arg);
@@ -1121,6 +1180,7 @@ public class WindowManagerShellCommand extends ShellCommand {
private void resetLetterboxStyle() {
synchronized (mInternal.mGlobalLock) {
mLetterboxConfiguration.resetFixedOrientationLetterboxAspectRatio();
+ mLetterboxConfiguration.resetDefaultMinAspectRatioForUnresizableApps();
mLetterboxConfiguration.resetLetterboxActivityCornersRadius();
mLetterboxConfiguration.resetLetterboxBackgroundType();
mLetterboxConfiguration.resetLetterboxBackgroundColor();
@@ -1132,6 +1192,7 @@ public class WindowManagerShellCommand extends ShellCommand {
mLetterboxConfiguration.resetDefaultPositionForHorizontalReachability();
mLetterboxConfiguration.resetDefaultPositionForVerticalReachability();
mLetterboxConfiguration.resetIsEducationEnabled();
+ mLetterboxConfiguration.resetIsSplitScreenAspectRatioForUnresizableAppsEnabled();
}
}
@@ -1145,6 +1206,8 @@ public class WindowManagerShellCommand extends ShellCommand {
+ mLetterboxConfiguration.getLetterboxVerticalPositionMultiplier());
pw.println("Aspect ratio: "
+ mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio());
+ pw.println("Default min aspect ratio for unresizable apps: "
+ + mLetterboxConfiguration.getDefaultMinAspectRatioForUnresizableApps());
pw.println("Is horizontal reachability enabled: "
+ mLetterboxConfiguration.getIsHorizontalReachabilityEnabled());
pw.println("Is vertical reachability enabled: "
@@ -1157,6 +1220,9 @@ public class WindowManagerShellCommand extends ShellCommand {
mLetterboxConfiguration.getDefaultPositionForVerticalReachability()));
pw.println("Is education enabled: "
+ mLetterboxConfiguration.getIsEducationEnabled());
+ pw.println("Is using split screen aspect ratio as aspect ratio for unresizable apps: "
+ + mLetterboxConfiguration
+ .getIsSplitScreenAspectRatioForUnresizableAppsEnabled());
pw.println("Background type: "
+ LetterboxConfiguration.letterboxBackgroundTypeToString(
@@ -1171,6 +1237,47 @@ public class WindowManagerShellCommand extends ShellCommand {
return 0;
}
+ private int runWmShellCommand(PrintWriter pw) {
+ String arg = getNextArg();
+
+ switch (arg) {
+ case "tracing":
+ return runWmShellTracing(pw);
+ case "help":
+ default:
+ return runHelp(pw);
+ }
+ }
+
+ private int runHelp(PrintWriter pw) {
+ pw.println("Window Manager Shell commands:");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println(" tracing <start/stop>");
+ pw.println(" Start/stop shell transition tracing.");
+
+ return 0;
+ }
+
+ private int runWmShellTracing(PrintWriter pw) {
+ String arg = getNextArg();
+
+ switch (arg) {
+ case "start":
+ mInternal.mTransitionTracer.startTrace(pw);
+ break;
+ case "stop":
+ mInternal.mTransitionTracer.stopTrace(pw);
+ break;
+ default:
+ getErrPrintWriter()
+ .println("Error: expected 'start' or 'stop', but got '" + arg + "'");
+ return -1;
+ }
+
+ return 0;
+ }
+
private int runReset(PrintWriter pw) throws RemoteException {
int displayId = getDisplayId(getNextArg());
@@ -1261,6 +1368,11 @@ public class WindowManagerShellCommand extends ShellCommand {
+ LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO);
pw.println(" both it and R.dimen.config_fixedOrientationLetterboxAspectRatio will");
pw.println(" be ignored and framework implementation will determine aspect ratio.");
+ pw.println(" --minAspectRatioForUnresizable aspectRatio");
+ pw.println(" Default min aspect ratio for unresizable apps which is used when an");
+ pw.println(" app doesn't specify android:minAspectRatio. An exception will be");
+ pw.println(" thrown if aspectRatio < "
+ + LetterboxConfiguration.MIN_UNRESIZABLE_ASPECT_RATIO);
pw.println(" --cornerRadius radius");
pw.println(" Corners radius for activities in the letterbox mode. If radius < 0,");
pw.println(" both it and R.integer.config_letterboxActivityCornersRadius will be");
@@ -1309,6 +1421,9 @@ public class WindowManagerShellCommand extends ShellCommand {
pw.println(" enabled.");
pw.println(" --isEducationEnabled [true|1|false|0]");
pw.println(" Whether education is allowed for letterboxed fullscreen apps.");
+ pw.println(" --isSplitScreenAspectRatioForUnresizableAppsEnabled [true|1|false|0]");
+ pw.println(" Whether using split screen aspect ratio as a default aspect ratio for");
+ pw.println(" unresizable apps.");
pw.println(" reset-letterbox-style [aspectRatio|cornerRadius|backgroundType");
pw.println(" |backgroundColor|wallpaperBlurRadius|wallpaperDarkScrimAlpha");
pw.println(" |horizontalPositionMultiplier|verticalPositionMultiplier");
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 8652bc8b7eb9..d4d8dd8bceb1 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.ActivityManager.isStartResultSuccessful;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
@@ -58,6 +59,7 @@ import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
@@ -117,7 +119,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
static final int CONTROLLABLE_CONFIGS = ActivityInfo.CONFIG_WINDOW_CONFIGURATION
| ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE | ActivityInfo.CONFIG_SCREEN_SIZE
| ActivityInfo.CONFIG_LAYOUT_DIRECTION;
- static final int CONTROLLABLE_WINDOW_CONFIGS = WindowConfiguration.WINDOW_CONFIG_BOUNDS
+ static final int CONTROLLABLE_WINDOW_CONFIGS = WINDOW_CONFIG_BOUNDS
| WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS;
private final ActivityTaskManagerService mService;
@@ -147,7 +149,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
void setWindowManager(WindowManagerService wms) {
- mTransitionController = new TransitionController(mService, wms.mTaskSnapshotController);
+ mTransitionController = new TransitionController(mService, wms.mTaskSnapshotController,
+ wms.mTransitionTracer);
mTransitionController.registerLegacyListener(wms.mActivityManagerAppTransitionNotifier);
}
@@ -446,7 +449,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
wc.asTask().setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */);
}
- int containerEffect = applyWindowContainerChange(wc, entry.getValue());
+ int containerEffect = applyWindowContainerChange(wc, entry.getValue(),
+ t.getErrorCallbackToken());
effects |= containerEffect;
if (forceHiddenForPip) {
@@ -530,7 +534,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
}
- private int applyChanges(WindowContainer container, WindowContainerTransaction.Change change) {
+ private int applyChanges(WindowContainer<?> container,
+ WindowContainerTransaction.Change change, @Nullable IBinder errorCallbackToken) {
// The "client"-facing API should prevent bad changes; however, just in case, sanitize
// masks here.
final int configMask = change.getConfigSetMask() & CONTROLLABLE_CONFIGS;
@@ -538,6 +543,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
int effects = 0;
final int windowingMode = change.getWindowingMode();
if (configMask != 0) {
+
+ adjustBoundsForMinDimensionsIfNeeded(container, change, errorCallbackToken);
+
if (windowingMode > -1 && windowingMode != container.getWindowingMode()) {
// Special handling for when we are setting a windowingMode in the same transaction.
// Setting the windowingMode is going to call onConfigurationChanged so we don't
@@ -590,6 +598,26 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
return effects;
}
+ private void adjustBoundsForMinDimensionsIfNeeded(WindowContainer<?> container,
+ WindowContainerTransaction.Change change, @Nullable IBinder errorCallbackToken) {
+ final TaskFragment taskFragment = container.asTaskFragment();
+ if (taskFragment == null || !taskFragment.isEmbedded()) {
+ return;
+ }
+ if ((change.getWindowSetMask() & WINDOW_CONFIG_BOUNDS) == 0) {
+ return;
+ }
+ final WindowConfiguration winConfig = change.getConfiguration().windowConfiguration;
+ final Rect bounds = winConfig.getBounds();
+ final Point minDimensions = taskFragment.calculateMinDimension();
+ if (bounds.width() < minDimensions.x || bounds.height() < minDimensions.y) {
+ sendMinimumDimensionViolation(taskFragment, minDimensions, errorCallbackToken,
+ "setBounds:" + bounds);
+ // Sets the bounds to match parent bounds.
+ winConfig.setBounds(new Rect());
+ }
+ }
+
private int applyTaskChanges(Task tr, WindowContainerTransaction.Change c) {
int effects = 0;
final SurfaceControl.Transaction t = c.getBoundsChangeTransaction();
@@ -752,7 +780,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final Bundle activityOptions = hop.getLaunchOptions();
final int result = mService.getActivityStartController()
.startActivityInTaskFragment(tf, activityIntent, activityOptions,
- hop.getCallingActivity(), caller.mUid, caller.mPid);
+ hop.getCallingActivity(), caller.mUid, caller.mPid,
+ errorCallbackToken);
if (!isStartResultSuccessful(result)) {
sendTaskFragmentOperationFailure(organizer, errorCallbackToken,
convertStartFailureToThrowable(result, activityIntent));
@@ -796,6 +825,12 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
break;
}
+ if (parent.smallerThanMinDimension(activity)) {
+ sendMinimumDimensionViolation(parent, activity.getMinDimensions(),
+ errorCallbackToken, "reparentActivityToTask");
+ break;
+ }
+
activity.reparent(parent, POSITION_TOP);
effects |= TRANSACT_EFFECTS_LIFECYCLE;
break;
@@ -862,22 +897,22 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
tf.getDisplayContent().setFocusedApp(targetFocus);
break;
}
- default: {
- // The other operations may change task order so they are skipped while in lock
- // task mode. The above operations are still allowed because they don't move
- // tasks. And it may be necessary such as clearing launch root after entering
- // lock task mode.
- if (isInLockTaskMode) {
- Slog.w(TAG, "Skip applying hierarchy operation " + hop
- + " while in lock task mode");
- return effects;
- }
- }
- }
-
- switch (type) {
case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: {
- effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId);
+ effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId,
+ isInLockTaskMode);
+ break;
+ }
+ case HIERARCHY_OP_TYPE_LAUNCH_TASK: {
+ mService.mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
+ "launchTask HierarchyOp");
+ final Bundle launchOpts = hop.getLaunchOptions();
+ final int taskId = launchOpts.getInt(
+ WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
+ launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
+ final SafeActivityOptions safeOptions =
+ SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid);
+ waitAsyncStart(() -> mService.mTaskSupervisor.startActivityFromRecents(
+ caller.mPid, caller.mUid, taskId, safeOptions));
break;
}
case HIERARCHY_OP_TYPE_REORDER:
@@ -887,6 +922,16 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
Slog.e(TAG, "Attempt to operate on detached container: " + wc);
break;
}
+ // There is no use case to ask the reparent operation in lock-task mode now, so keep
+ // skipping this operation as usual.
+ if (isInLockTaskMode && type == HIERARCHY_OP_TYPE_REPARENT) {
+ Slog.w(TAG, "Skip applying hierarchy operation " + hop
+ + " while in lock task mode");
+ break;
+ }
+ if (isLockTaskModeViolation(wc.getParent(), wc.asTask(), isInLockTaskMode)) {
+ break;
+ }
if (syncId >= 0) {
addToSyncSet(syncId, wc);
}
@@ -912,19 +957,20 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
effects |= sanitizeAndApplyHierarchyOp(wc, hop);
break;
}
- case HIERARCHY_OP_TYPE_LAUNCH_TASK: {
- mService.mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
- "launchTask HierarchyOp");
- final Bundle launchOpts = hop.getLaunchOptions();
- final int taskId = launchOpts.getInt(
- WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
- launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
- final SafeActivityOptions safeOptions =
- SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid);
- waitAsyncStart(() -> mService.mTaskSupervisor.startActivityFromRecents(
- caller.mPid, caller.mUid, taskId, safeOptions));
- break;
+ default: {
+ // The other operations may change task order so they are skipped while in lock
+ // task mode. The above operations are still allowed because they don't move
+ // tasks. And it may be necessary such as clearing launch root after entering
+ // lock task mode.
+ if (isInLockTaskMode) {
+ Slog.w(TAG, "Skip applying hierarchy operation " + hop
+ + " while in lock task mode");
+ return effects;
+ }
}
+ }
+
+ switch (type) {
case HIERARCHY_OP_TYPE_PENDING_INTENT: {
String resolvedType = hop.getActivityIntent() != null
? hop.getActivityIntent().resolveTypeIfNeeded(
@@ -1009,6 +1055,19 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
return effects;
}
+ /** A helper method to send minimum dimension violation error to the client. */
+ void sendMinimumDimensionViolation(TaskFragment taskFragment, Point minDimensions,
+ IBinder errorCallbackToken, String reason) {
+ if (taskFragment == null || taskFragment.getTaskFragmentOrganizer() == null) {
+ return;
+ }
+ final Throwable exception = new SecurityException("The task fragment's bounds:"
+ + taskFragment.getBounds() + " does not satisfy minimum dimensions:"
+ + minDimensions + " " + reason);
+ sendTaskFragmentOperationFailure(taskFragment.getTaskFragmentOrganizer(),
+ errorCallbackToken, exception);
+ }
+
/**
* Post and wait for the result of the activity start to prevent potential deadlock against
* {@link WindowManagerGlobalLock}.
@@ -1103,8 +1162,25 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
return TRANSACT_EFFECTS_LIFECYCLE;
}
+ private boolean isLockTaskModeViolation(WindowContainer parent, Task task,
+ boolean isInLockTaskMode) {
+ if (!isInLockTaskMode || parent == null || task == null) {
+ return false;
+ }
+ final LockTaskController lockTaskController = mService.getLockTaskController();
+ boolean taskViolation = lockTaskController.isLockTaskModeViolation(task);
+ if (!taskViolation && parent.asTask() != null) {
+ taskViolation = lockTaskController.isLockTaskModeViolation(parent.asTask());
+ }
+ if (taskViolation) {
+ Slog.w(TAG, "Can't support the operation since in lock task mode violation. "
+ + " Task: " + task + " Parent : " + parent);
+ }
+ return taskViolation;
+ }
+
private int reparentChildrenTasksHierarchyOp(WindowContainerTransaction.HierarchyOp hop,
- @Nullable Transition transition, int syncId) {
+ @Nullable Transition transition, int syncId, boolean isInLockTaskMode) {
WindowContainer<?> currentParent = hop.getContainer() != null
? WindowContainer.fromBinder(hop.getContainer()) : null;
WindowContainer newParent = hop.getNewParent() != null
@@ -1142,6 +1218,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
? newParent.asTask().getDisplayArea()
: newParent.asTaskDisplayArea();
final WindowContainer finalCurrentParent = currentParent;
+ final WindowContainer finalNewParent = newParent;
Slog.i(TAG, "reparentChildrenTasksHierarchyOp"
+ " currentParent=" + currentParent + " newParent=" + newParent + " hop=" + hop);
@@ -1165,6 +1242,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|| !ArrayUtils.contains(hop.getWindowingModes(), task.getWindowingMode())) {
return false;
}
+ if (isLockTaskModeViolation(finalNewParent, task, isInLockTaskMode)) {
+ return false;
+ }
if (hop.getToTop()) {
tasksToReparent.add(0, task);
@@ -1220,14 +1300,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
private int applyWindowContainerChange(WindowContainer wc,
- WindowContainerTransaction.Change c) {
+ WindowContainerTransaction.Change c, @Nullable IBinder errorCallbackToken) {
sanitizeWindowContainer(wc);
if (wc.asTaskFragment() != null && wc.asTaskFragment().isEmbeddedTaskFragmentInPip()) {
// No override from organizer for embedded TaskFragment in a PIP Task.
return 0;
}
- int effects = applyChanges(wc, c);
+ int effects = applyChanges(wc, c, errorCallbackToken);
if (wc instanceof DisplayArea) {
effects |= applyDisplayAreaChanges(wc.asDisplayArea(), c);
@@ -1571,8 +1651,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
mLaunchTaskFragments.put(creationParams.getFragmentToken(), taskFragment);
}
- void reparentTaskFragment(@NonNull TaskFragment oldParent, @Nullable WindowContainer newParent,
- @Nullable ITaskFragmentOrganizer organizer, @Nullable IBinder errorCallbackToken) {
+ void reparentTaskFragment(@NonNull TaskFragment oldParent,
+ @Nullable WindowContainer<?> newParent, @Nullable ITaskFragmentOrganizer organizer,
+ @Nullable IBinder errorCallbackToken) {
final TaskFragment newParentTF;
if (newParent == null) {
// Use the old parent's parent if the caller doesn't specify the new parent.
@@ -1610,6 +1691,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
return;
}
+ final Point minDimensions = oldParent.calculateMinDimension();
+ final Rect newParentBounds = newParentTF.getBounds();
+ if (newParentBounds.width() < minDimensions.x
+ || newParentBounds.height() < minDimensions.y) {
+ sendMinimumDimensionViolation(newParentTF, minDimensions, errorCallbackToken,
+ "reparentTaskFragment");
+ return;
+ }
while (oldParent.hasChild()) {
oldParent.getChildAt(0).reparent(newParentTF, POSITION_TOP);
}
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 8fed270c6a1c..3ff912cca091 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -25,7 +25,6 @@ import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.server.am.ActivityManagerService.MY_PID;
import static com.android.server.wm.ActivityRecord.State.DESTROYED;
import static com.android.server.wm.ActivityRecord.State.DESTROYING;
import static com.android.server.wm.ActivityRecord.State.PAUSED;
@@ -40,6 +39,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
+import static com.android.server.wm.WindowManagerService.MY_PID;
import android.Manifest;
import android.annotation.NonNull;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index a35d2857748b..c91bec9fb0c9 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -116,7 +116,6 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RESIZE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_INSETS;
-import static com.android.server.am.ActivityManagerService.MY_PID;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER;
import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
@@ -151,6 +150,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.WINDOW_STATE_BLAST_SYNC_TIMEOUT;
import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
+import static com.android.server.wm.WindowManagerService.MY_PID;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 870257802608..9f7cbf3c9cd4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -9290,22 +9290,39 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return poComponent;
}
}
- final String supervisor = mContext.getResources().getString(
- com.android.internal.R.string.config_defaultSupervisionProfileOwnerComponent);
- if (supervisor == null) {
- return null;
+
+ // Check profile owner first as that is what most likely is set.
+ if (isSupervisionComponent(poComponent)) {
+ return poComponent;
}
- final ComponentName supervisorComponent = ComponentName.unflattenFromString(supervisor);
- if (supervisorComponent == null) {
- return null;
+
+ if (isSupervisionComponent(doComponent)) {
+ return doComponent;
}
- if (supervisorComponent.equals(doComponent) || supervisorComponent.equals(
- poComponent)) {
- return supervisorComponent;
- } else {
- return null;
+
+ return null;
+ }
+ }
+
+ private boolean isSupervisionComponent(@Nullable ComponentName who) {
+ if (who == null) {
+ return false;
+ }
+
+ final String configComponent = mContext.getResources().getString(
+ com.android.internal.R.string.config_defaultSupervisionProfileOwnerComponent);
+ if (configComponent != null) {
+ final ComponentName componentName = ComponentName.unflattenFromString(configComponent);
+ if (who.equals(componentName)) {
+ return true;
}
}
+
+ // Check the system supervision role.
+ final String configPackage = mContext.getResources().getString(
+ com.android.internal.R.string.config_systemSupervision);
+
+ return who.getPackageName().equals(configPackage);
}
@Override
@@ -9491,22 +9508,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
"Cannot set the profile owner on a user which is already set-up");
if (!mIsWatch) {
- final String supervisionRolePackage = mContext.getResources().getString(
- com.android.internal.R.string.config_systemSupervision);
- // Only the default supervision profile owner or supervision role holder
- // can be set as profile owner after SUW
- final String supervisor = mContext.getResources().getString(
- com.android.internal.R.string
- .config_defaultSupervisionProfileOwnerComponent);
- if (supervisor == null && supervisionRolePackage == null) {
- throw new IllegalStateException("Unable to set profile owner post-setup, no"
- + "default supervisor profile owner defined");
- }
-
- final ComponentName supervisorComponent = ComponentName.unflattenFromString(
- supervisor);
- if (!owner.equals(supervisorComponent)
- && !owner.getPackageName().equals(supervisionRolePackage)) {
+ if (!isSupervisionComponent(owner)) {
throw new IllegalStateException("Unable to set non-default profile owner"
+ " post-setup " + owner);
}
@@ -12100,7 +12102,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
synchronized (getLockObject()) {
// Allow testOnly admins to bypass supervision config requirement.
Preconditions.checkCallAuthorization(isAdminTestOnlyLocked(who, caller.getUserId())
- || isDefaultSupervisor(caller), "Admin %s is not the "
+ || isSupervisionComponent(caller.getComponentName()), "Admin %s is not the "
+ "default supervision component", caller.getComponentName());
DevicePolicyData policy = getUserData(caller.getUserId());
policy.mSecondaryLockscreenEnabled = enabled;
@@ -12119,16 +12121,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return isProfileOwner(caller) && isManagedProfile(caller.getUserId());
}
- private boolean isDefaultSupervisor(CallerIdentity caller) {
- final String supervisor = mContext.getResources().getString(
- com.android.internal.R.string.config_defaultSupervisionProfileOwnerComponent);
- if (supervisor == null) {
- return false;
- }
- final ComponentName supervisorComponent = ComponentName.unflattenFromString(supervisor);
- return caller.getComponentName().equals(supervisorComponent);
- }
-
@Override
public void setPreferentialNetworkServiceConfigs(
List<PreferentialNetworkServiceConfig> preferentialNetworkServiceConfigs) {
@@ -12517,8 +12509,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
.setContentIntent(locationSettingsIntent)
.setAutoCancel(true)
.build();
- mInjector.getNotificationManager().notify(SystemMessage.NOTE_LOCATION_CHANGED,
- notification);
+ mHandler.post(() -> mInjector.getNotificationManager().notify(
+ SystemMessage.NOTE_LOCATION_CHANGED, notification));
}
private String getLocationChangedTitle() {
@@ -13012,16 +13004,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
- final String supervisionString = mContext.getResources().getString(
- com.android.internal.R.string
- .config_defaultSupervisionProfileOwnerComponent);
- if (supervisionString == null) {
- return false;
- }
-
- final ComponentName supervisorComponent = ComponentName.unflattenFromString(
- supervisionString);
- return admin.info.getComponent().equals(supervisorComponent);
+ return isSupervisionComponent(admin.info.getComponent());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java b/services/tests/servicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java
new file mode 100644
index 000000000000..94742537ed1a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.fullbackup;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.backup.TransportManager;
+import com.android.server.backup.UserBackupManagerService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class PerformFullTransportBackupTaskTest {
+ @Mock
+ UserBackupManagerService mBackupManagerService;
+ @Mock
+ TransportManager mTransportManager;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mBackupManagerService.getTransportManager()).thenReturn(mTransportManager);
+ }
+
+ @Test
+ public void testNewWithCurrentTransport_noTransportConnection_throws() {
+ when(mTransportManager.getCurrentTransportClient(any())).thenReturn(null);
+
+ assertThrows(IllegalStateException.class,
+ () -> {
+ PerformFullTransportBackupTask task = PerformFullTransportBackupTask
+ .newWithCurrentTransport(
+ mBackupManagerService,
+ /* operationStorage */ null,
+ /* observer */ null,
+ /* whichPackages */ null,
+ /* updateSchedule */ false,
+ /* runningJob */ null,
+ /* latch */ null,
+ /* backupObserver */ null,
+ /* monitor */ null,
+ /* userInitiated */ false,
+ /* caller */ null,
+ /* backupEligibilityRules */ null);
+ });
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index f9671e56fe12..f242fda15f06 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -228,36 +228,36 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void onVirtualDisplayRemovedLocked_doesNotThrowException() {
- final int displayId = 2;
- mDeviceImpl.onVirtualDisplayCreatedLocked(displayId);
+ mDeviceImpl.onVirtualDisplayCreatedLocked(
+ mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
// This call should not throw any exceptions.
- mDeviceImpl.onVirtualDisplayRemovedLocked(displayId);
+ mDeviceImpl.onVirtualDisplayRemovedLocked(DISPLAY_ID);
}
@Test
public void onVirtualDisplayCreatedLocked_wakeLockIsAcquired() throws RemoteException {
- final int displayId = 2;
- mDeviceImpl.onVirtualDisplayCreatedLocked(displayId);
verify(mIPowerManagerMock, never()).acquireWakeLock(any(Binder.class), anyInt(),
nullable(String.class), nullable(String.class), nullable(WorkSource.class),
nullable(String.class), anyInt(), eq(null));
- TestableLooper.get(this).processAllMessages();
+ mDeviceImpl.onVirtualDisplayCreatedLocked(
+ mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(any(Binder.class), anyInt(),
nullable(String.class), nullable(String.class), nullable(WorkSource.class),
- nullable(String.class), eq(displayId), eq(null));
+ nullable(String.class), eq(DISPLAY_ID), eq(null));
}
@Test
public void onVirtualDisplayCreatedLocked_duplicateCalls_onlyOneWakeLockIsAcquired()
throws RemoteException {
- final int displayId = 2;
- mDeviceImpl.onVirtualDisplayCreatedLocked(displayId);
+ GenericWindowPolicyController gwpc = mDeviceImpl.createWindowPolicyController();
+ mDeviceImpl.onVirtualDisplayCreatedLocked(
+ mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
assertThrows(IllegalStateException.class,
- () -> mDeviceImpl.onVirtualDisplayCreatedLocked(displayId));
+ () -> mDeviceImpl.onVirtualDisplayCreatedLocked(gwpc, DISPLAY_ID));
TestableLooper.get(this).processAllMessages();
verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(any(Binder.class), anyInt(),
nullable(String.class), nullable(String.class), nullable(WorkSource.class),
- nullable(String.class), eq(displayId), eq(null));
+ nullable(String.class), eq(DISPLAY_ID), eq(null));
}
@Test
@@ -269,30 +269,30 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void onVirtualDisplayRemovedLocked_wakeLockIsReleased() throws RemoteException {
- final int displayId = 2;
- mDeviceImpl.onVirtualDisplayCreatedLocked(displayId);
+ mDeviceImpl.onVirtualDisplayCreatedLocked(
+ mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class);
TestableLooper.get(this).processAllMessages();
verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(wakeLockCaptor.capture(),
anyInt(),
nullable(String.class), nullable(String.class), nullable(WorkSource.class),
- nullable(String.class), eq(displayId), eq(null));
+ nullable(String.class), eq(DISPLAY_ID), eq(null));
IBinder wakeLock = wakeLockCaptor.getValue();
- mDeviceImpl.onVirtualDisplayRemovedLocked(displayId);
+ mDeviceImpl.onVirtualDisplayRemovedLocked(DISPLAY_ID);
verify(mIPowerManagerMock, Mockito.times(1)).releaseWakeLock(eq(wakeLock), anyInt());
}
@Test
public void addVirtualDisplay_displayNotReleased_wakeLockIsReleased() throws RemoteException {
- final int displayId = 2;
- mDeviceImpl.onVirtualDisplayCreatedLocked(displayId);
+ mDeviceImpl.onVirtualDisplayCreatedLocked(
+ mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class);
TestableLooper.get(this).processAllMessages();
verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(wakeLockCaptor.capture(),
anyInt(),
nullable(String.class), nullable(String.class), nullable(WorkSource.class),
- nullable(String.class), eq(displayId), eq(null));
+ nullable(String.class), eq(DISPLAY_ID), eq(null));
IBinder wakeLock = wakeLockCaptor.getValue();
// Close the VirtualDevice without first notifying it of the VirtualDisplay removal.
@@ -416,7 +416,8 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void onAudioSessionStarting_hasVirtualAudioController() {
- mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
+ mDeviceImpl.onVirtualDisplayCreatedLocked(
+ mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mRoutingCallback, mConfigChangedCallback);
@@ -425,7 +426,8 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void onAudioSessionEnded_noVirtualAudioController() {
- mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
+ mDeviceImpl.onVirtualDisplayCreatedLocked(
+ mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mRoutingCallback, mConfigChangedCallback);
mDeviceImpl.onAudioSessionEnded();
@@ -435,7 +437,8 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void close_cleanVirtualAudioController() {
- mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
+ mDeviceImpl.onVirtualDisplayCreatedLocked(
+ mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mRoutingCallback, mConfigChangedCallback);
mDeviceImpl.close();
@@ -659,7 +662,8 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void openNonBlockedAppOnVirtualDisplay_doesNotStartBlockedAlertActivity() {
- mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
+ mDeviceImpl.onVirtualDisplayCreatedLocked(
+ mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID);
doNothing().when(mContext).startActivityAsUser(any(), any(), any());
@@ -677,7 +681,8 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void openPermissionControllerOnVirtualDisplay_startBlockedAlertActivity() {
- mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
+ mDeviceImpl.onVirtualDisplayCreatedLocked(
+ mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID);
doNothing().when(mContext).startActivityAsUser(any(), any(), any());
@@ -695,7 +700,8 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void openSettingsOnVirtualDisplay_startBlockedAlertActivity() {
- mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
+ mDeviceImpl.onVirtualDisplayCreatedLocked(
+ mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID);
doNothing().when(mContext).startActivityAsUser(any(), any(), any());
@@ -713,7 +719,8 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void openVendingOnVirtualDisplay_startBlockedAlertActivity() {
- mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
+ mDeviceImpl.onVirtualDisplayCreatedLocked(
+ mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID);
doNothing().when(mContext).startActivityAsUser(any(), any(), any());
@@ -731,7 +738,8 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void openGoogleDialerOnVirtualDisplay_startBlockedAlertActivity() {
- mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
+ mDeviceImpl.onVirtualDisplayCreatedLocked(
+ mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID);
doNothing().when(mContext).startActivityAsUser(any(), any(), any());
@@ -749,7 +757,8 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void openGoogleMapsOnVirtualDisplay_startBlockedAlertActivity() {
- mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID);
+ mDeviceImpl.onVirtualDisplayCreatedLocked(
+ mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
DISPLAY_ID);
doNothing().when(mContext).startActivityAsUser(any(), any(), any());
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
index cd836c77076d..e2c3a94fc187 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
@@ -16,6 +16,7 @@
package com.android.server.companion.virtual.audio;
+import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING;
import static android.media.AudioAttributes.FLAG_SECURE;
import static android.media.AudioPlaybackConfiguration.PLAYER_STATE_STARTED;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
@@ -81,7 +82,8 @@ public class VirtualAudioControllerTest {
/* blockedActivities= */ new ArraySet<>(),
VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED,
/* activityListener= */ null,
- /* activityBlockedCallback= */ null);
+ /* activityBlockedCallback= */ null,
+ /* deviceProfile= */ DEVICE_PROFILE_APP_STREAMING);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index ec6b67450a1a..8014d2502f48 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3322,19 +3322,48 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
- public void testIsActiveSupervisionApp() throws Exception {
- when(mServiceContext.resources
- .getString(R.string.config_defaultSupervisionProfileOwnerComponent))
- .thenReturn(admin1.flattenToString());
+ public void testSupervisionConfig() throws Exception {
+ final int uid = UserHandle.getUid(15, 19436);
+ addManagedProfile(admin1, uid, admin1);
+ mContext.binder.callingUid = uid;
- final int PROFILE_USER = 15;
- final int PROFILE_ADMIN = UserHandle.getUid(PROFILE_USER, 19436);
- addManagedProfile(admin1, PROFILE_ADMIN, admin1);
- mContext.binder.callingUid = PROFILE_ADMIN;
+ verifySupervisionConfig(uid, null, null);
+ verifySupervisionConfig(uid, "", null);
+ verifySupervisionConfig(uid, null, "");
+ verifySupervisionConfig(uid, "", "");
+
+ verifySupervisionConfig(uid, admin1.flattenToString(), null);
+ verifySupervisionConfig(uid, admin1.flattenToString(), "");
+
+ verifySupervisionConfig(uid, null, admin1.getPackageName());
+ verifySupervisionConfig(uid, "", admin1.getPackageName());
+ }
+
+ private void verifySupervisionConfig(
+ int uid , String configComponentName, String configPackageName) {
+ final boolean isAdmin = admin1.flattenToString().equals(configComponentName)
+ || admin1.getPackageName().equals(configPackageName);
+ final UserHandle user = UserHandle.getUserHandleForUid(uid);
final DevicePolicyManagerInternal dpmi =
LocalServices.getService(DevicePolicyManagerInternal.class);
- assertThat(dpmi.isActiveSupervisionApp(PROFILE_ADMIN)).isTrue();
+
+ when(mServiceContext.resources
+ .getString(R.string.config_defaultSupervisionProfileOwnerComponent))
+ .thenReturn(configComponentName);
+
+ when(mServiceContext.resources
+ .getString(R.string.config_systemSupervision))
+ .thenReturn(configPackageName);
+
+ if (isAdmin) {
+ assertThat(dpmi.isActiveSupervisionApp(uid)).isTrue();
+ assertThat(dpm.getProfileOwnerOrDeviceOwnerSupervisionComponent(user))
+ .isEqualTo(admin1);
+ } else {
+ assertThat(dpmi.isActiveSupervisionApp(uid)).isFalse();
+ assertThat(dpm.getProfileOwnerOrDeviceOwnerSupervisionComponent(user)).isNull();
+ }
}
// Test if lock timeout on managed profile is handled correctly depending on whether profile
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 6f48368c6ab2..1e97c1c5c5bc 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -45,6 +45,7 @@ import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.Curve;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
+import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayViewport;
import android.hardware.display.DisplayedContentSample;
import android.hardware.display.DisplayedContentSamplingAttributes;
@@ -63,6 +64,7 @@ import android.view.DisplayEventReceiver;
import android.view.DisplayInfo;
import android.view.Surface;
import android.view.SurfaceControl;
+import android.window.DisplayWindowPolicyController;
import androidx.test.InstrumentationRegistry;
import androidx.test.core.app.ApplicationProvider;
@@ -220,7 +222,7 @@ public class DisplayManagerServiceTest {
builder.setUniqueId(uniqueId);
builder.setFlags(flags);
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
- null /* projection */, null /* virtualDeviceToken */, PACKAGE_NAME);
+ null /* projection */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -346,7 +348,7 @@ public class DisplayManagerServiceTest {
builder.setFlags(flags);
builder.setUniqueId(uniqueId);
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
- null /* projection */, null /* virtualDeviceToken */, PACKAGE_NAME);
+ null /* projection */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -586,8 +588,7 @@ public class DisplayManagerServiceTest {
VIRTUAL_DISPLAY_NAME, width, height, dpi);
builder.setUniqueId(uniqueId);
final int firstDisplayId = binderService.createVirtualDisplay(builder.build(),
- mMockAppToken /* callback */, null /* projection */, null /* virtualDeviceToken */,
- PACKAGE_NAME);
+ mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
// The second virtual display requests to mirror the first virtual display.
final String uniqueId2 = "uniqueId --- displayIdToMirrorTest #2";
@@ -598,7 +599,7 @@ public class DisplayManagerServiceTest {
builder2.setDisplayIdToMirror(firstDisplayId);
final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(),
mMockAppToken2 /* callback */, null /* projection */,
- null /* virtualDeviceToken */, PACKAGE_NAME);
+ PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
// flush the handler
@@ -636,8 +637,7 @@ public class DisplayManagerServiceTest {
builder.setSurface(surface);
builder.setUniqueId(uniqueId);
final int displayId = binderService.createVirtualDisplay(builder.build(),
- mMockAppToken /* callback */, null /* projection */, null /* virtualDeviceToken */,
- PACKAGE_NAME);
+ mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -669,7 +669,7 @@ public class DisplayManagerServiceTest {
builder.setUniqueId("uniqueId --- OWN_DISPLAY_GROUP");
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
- null /* projection */, null /* virtualDeviceToken */, PACKAGE_NAME);
+ null /* projection */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
@@ -700,7 +700,7 @@ public class DisplayManagerServiceTest {
try {
bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
- null /* projection */, null /* virtualDeviceToken */, PACKAGE_NAME);
+ null /* projection */, PACKAGE_NAME);
fail("Creating virtual display with VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP without "
+ "ADD_TRUSTED_DISPLAY permission should throw SecurityException.");
} catch (SecurityException e) {
@@ -716,6 +716,8 @@ public class DisplayManagerServiceTest {
public void testOwnDisplayGroup_allowCreationWithVirtualDevice() {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
+ DisplayManagerInternal localService = displayManager.new LocalService();
+
registerDefaultDisplays(displayManager);
DisplayManagerService.BinderService bs = displayManager.new BinderService();
@@ -733,8 +735,9 @@ public class DisplayManagerServiceTest {
when(mMockVirtualDeviceManagerInternal.isValidVirtualDevice(virtualDevice))
.thenReturn(true);
- int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
- null /* projection */, virtualDevice /* virtualDeviceToken */, PACKAGE_NAME);
+ int displayId = localService.createVirtualDisplay(builder.build(),
+ mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */,
+ mock(DisplayWindowPolicyController.class), PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
diff --git a/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java b/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
index 57a9cb278c80..9fe8609c85a1 100644
--- a/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
@@ -24,6 +24,8 @@ import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.hardware.display.BrightnessConfiguration;
+import android.os.Handler;
+import android.os.test.TestLooper;
import android.util.Pair;
import androidx.test.InstrumentationRegistry;
@@ -47,11 +49,14 @@ import java.nio.charset.StandardCharsets;
public class PersistentDataStoreTest {
private PersistentDataStore mDataStore;
private TestInjector mInjector;
+ private TestLooper mTestLooper;
@Before
public void setUp() {
mInjector = new TestInjector();
- mDataStore = new PersistentDataStore(mInjector);
+ mTestLooper = new TestLooper();
+ Handler handler = new Handler(mTestLooper.getLooper());
+ mDataStore = new PersistentDataStore(mInjector, handler);
}
@Test
@@ -147,7 +152,7 @@ public class PersistentDataStoreTest {
}
@Test
- public void testStoreAndReloadOfDisplayBrightnessConfigurations() {
+ public void testStoreAndReloadOfDisplayBrightnessConfigurations() throws InterruptedException {
final String uniqueDisplayId = "test:123";
int userSerial = 0;
String packageName = "pdsTestPackage";
@@ -178,6 +183,7 @@ public class PersistentDataStoreTest {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
mInjector.setWriteStream(baos);
mDataStore.saveIfNeeded();
+ mTestLooper.dispatchAll();
assertTrue(mInjector.wasWriteSuccessful());
TestInjector newInjector = new TestInjector();
PersistentDataStore newDataStore = new PersistentDataStore(newInjector);
@@ -222,7 +228,7 @@ public class PersistentDataStoreTest {
}
@Test
- public void testStoreAndReloadOfBrightnessConfigurations() {
+ public void testStoreAndReloadOfBrightnessConfigurations() throws InterruptedException {
final float[] lux = { 0f, 10f };
final float[] nits = {1f, 100f };
final BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits)
@@ -238,6 +244,7 @@ public class PersistentDataStoreTest {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
mInjector.setWriteStream(baos);
mDataStore.saveIfNeeded();
+ mTestLooper.dispatchAll();
assertTrue(mInjector.wasWriteSuccessful());
TestInjector newInjector = new TestInjector();
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java
index 9674ebd75677..facbe80bde67 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java
@@ -1336,6 +1336,46 @@ public class AppsFilterImplTest {
}
+ @Test
+ public void testSdkSandbox_canSeeForceQueryable() throws Exception {
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null,
+ mMockHandler);
+ simulateAddBasicAndroid(appsFilter);
+ appsFilter.onSystemReady(mPmInternal);
+
+ PackageSetting target = simulateAddPackage(appsFilter,
+ pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_APPID,
+ setting -> setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM));
+
+ int callingUid = 20123;
+ assertTrue(Process.isSdkSandboxUid(callingUid));
+
+ assertFalse(
+ appsFilter.shouldFilterApplication(mSnapshot, callingUid,
+ null /* callingSetting */, target, SYSTEM_USER));
+ }
+
+ @Test
+ public void testSdkSandbox_cannotSeeNonForceQueryable() throws Exception {
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null,
+ mMockHandler);
+ simulateAddBasicAndroid(appsFilter);
+ appsFilter.onSystemReady(mPmInternal);
+
+ PackageSetting target = simulateAddPackage(appsFilter,
+ pkg("com.some.package"), DUMMY_TARGET_APPID,
+ setting -> setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM));
+
+ int callingUid = 20123;
+ assertTrue(Process.isSdkSandboxUid(callingUid));
+
+ assertTrue(
+ appsFilter.shouldFilterApplication(mSnapshot, callingUid,
+ null /* callingSetting */, target, SYSTEM_USER));
+ }
+
private List<Integer> toList(int[] array) {
ArrayList<Integer> ret = new ArrayList<>(array.length);
for (int i = 0; i < array.length; i++) {
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 0d56975f51d0..22721a1bcc92 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -6227,13 +6227,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// first time trying to show the toast, showToast gets called
nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null);
verify(mStatusBar, times(1))
- .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any());
+ .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
// second time trying to show the same toast, showToast isn't called again (total number of
// invocations stays at one)
nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null);
verify(mStatusBar, times(1))
- .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any());
+ .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
}
@Test
@@ -6255,7 +6255,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null);
verify(mStatusBar, times(0))
- .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any());
+ .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
}
@Test
@@ -6277,7 +6277,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null);
verify(mStatusBar, times(1))
- .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any());
+ .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
}
@Test
@@ -6297,7 +6297,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
INotificationManager nmService = (INotificationManager) mService.mService;
nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null);
- verify(mStatusBar).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any());
+ verify(mStatusBar).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(),
+ anyInt());
}
@Test
@@ -6326,7 +6327,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// but never shown
verify(mStatusBar, times(0))
- .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any());
+ .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt());
// and removed when rate limited
verify(mWindowManagerInternal)
@@ -6417,7 +6418,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// enqueue toast -> no toasts enqueued
((INotificationManager) mService.mService).enqueueTextToast(testPackage, new Binder(),
"Text", 2000, 0, null);
- verify(mStatusBar).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any());
+ verify(mStatusBar).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(),
+ anyInt());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index b8f0b72b24a7..19f25c6bef9a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -756,8 +756,8 @@ public class ActivityRecordTests extends WindowTestsBase {
final ActivityRecord activity = createActivityWithTask();
ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(activity.getTask()).build();
topActivity.setOccludesParent(false);
- // The requested occluding state doesn't affect whether it fills parent.
- assertTrue(topActivity.fillsParent());
+ // The requested occluding state doesn't affect whether it can decide orientation.
+ assertTrue(topActivity.providesOrientation());
activity.setState(STOPPED, "Testing");
activity.setVisibility(true);
activity.makeActiveIfNeeded(null /* activeActivity */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 35921585d56f..436cf36587d8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_CHANGE;
@@ -25,6 +27,7 @@ import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_NONE;
+import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
@@ -409,38 +412,50 @@ public class AppTransitionTests extends WindowTestsBase {
}
@Test
- public void testDelayWhileRecents() {
+ public void testExcludeLauncher() {
final DisplayContent dc = createNewDisplay(Display.STATE_ON);
doReturn(false).when(dc).onDescendantOrientationChanged(any());
final Task task = createTask(dc);
- // Simulate activity1 launches activity2.
+ // Simulate activity1 launches activity2
final ActivityRecord activity1 = createActivityRecord(task);
activity1.setVisible(true);
activity1.mVisibleRequested = false;
activity1.allDrawn = true;
+ dc.mClosingApps.add(activity1);
final ActivityRecord activity2 = createActivityRecord(task);
activity2.setVisible(false);
activity2.mVisibleRequested = true;
activity2.allDrawn = true;
-
- dc.mClosingApps.add(activity1);
dc.mOpeningApps.add(activity2);
dc.prepareAppTransition(TRANSIT_OPEN);
- assertTrue(dc.mAppTransition.containsTransitRequest(TRANSIT_OPEN));
+
+ // Simulate start recents
+ final ActivityRecord homeActivity = createActivityRecord(dc, WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_HOME);
+ homeActivity.setVisible(false);
+ homeActivity.mVisibleRequested = true;
+ homeActivity.allDrawn = true;
+ dc.mOpeningApps.add(homeActivity);
+ dc.prepareAppTransition(TRANSIT_NONE);
+ doReturn(true).when(task)
+ .isSelfAnimating(anyInt(), eq(ANIMATION_TYPE_RECENTS));
// Wait until everything in animation handler get executed to prevent the exiting window
// from being removed during WindowSurfacePlacer Traversal.
waitUntilHandlersIdle();
- // Start recents
- doReturn(true).when(task)
- .isSelfAnimating(anyInt(), eq(ANIMATION_TYPE_RECENTS));
-
dc.mAppTransitionController.handleAppTransitionReady();
- verify(activity1, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean());
- verify(activity2, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean());
+ verify(activity1).commitVisibility(eq(false), anyBoolean(), anyBoolean());
+ verify(activity1).applyAnimation(any(), eq(TRANSIT_OLD_ACTIVITY_OPEN), eq(false),
+ anyBoolean(), any());
+ verify(activity2).commitVisibility(eq(true), anyBoolean(), anyBoolean());
+ verify(activity2).applyAnimation(any(), eq(TRANSIT_OLD_ACTIVITY_OPEN), eq(true),
+ anyBoolean(), any());
+ verify(homeActivity).commitVisibility(eq(true), anyBoolean(), anyBoolean());
+ verify(homeActivity, never()).applyAnimation(any(), anyInt(), anyBoolean(), anyBoolean(),
+ any());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 403a3ecd04ee..b27060872baa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -79,7 +79,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_FIXED_TRANSFORM;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_TOKEN_TRANSFORM;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -1460,7 +1460,7 @@ public class DisplayContentTests extends WindowTestsBase {
displayContent.setRotationAnimation(rotationAnim);
// The fade rotation animation also starts to hide some non-app windows.
assertNotNull(displayContent.getAsyncRotationController());
- assertTrue(statusBar.isAnimating(PARENTS, ANIMATION_TYPE_FIXED_TRANSFORM));
+ assertTrue(statusBar.isAnimating(PARENTS, ANIMATION_TYPE_TOKEN_TRANSFORM));
for (WindowState w : windows) {
w.setOrientationChanging(true);
@@ -1514,10 +1514,10 @@ public class DisplayContentTests extends WindowTestsBase {
final AsyncRotationController asyncRotationController =
mDisplayContent.getAsyncRotationController();
assertNotNull(asyncRotationController);
- assertTrue(mStatusBarWindow.isAnimating(PARENTS, ANIMATION_TYPE_FIXED_TRANSFORM));
- assertTrue(mNavBarWindow.isAnimating(PARENTS, ANIMATION_TYPE_FIXED_TRANSFORM));
+ assertTrue(mStatusBarWindow.isAnimating(PARENTS, ANIMATION_TYPE_TOKEN_TRANSFORM));
+ assertTrue(mNavBarWindow.isAnimating(PARENTS, ANIMATION_TYPE_TOKEN_TRANSFORM));
// Notification shade may have its own view animation in real case so do not fade out it.
- assertFalse(mNotificationShadeWindow.isAnimating(PARENTS, ANIMATION_TYPE_FIXED_TRANSFORM));
+ assertFalse(mNotificationShadeWindow.isAnimating(PARENTS, ANIMATION_TYPE_TOKEN_TRANSFORM));
// If the visibility of insets state is changed, the rotated state should be updated too.
final InsetsState rotatedState = app.getFixedRotationTransformInsetsState();
@@ -1588,7 +1588,7 @@ public class DisplayContentTests extends WindowTestsBase {
app.token, app.token, mDisplayContent.mDisplayId);
assertTrue(asyncRotationController.isTargetToken(mImeWindow.mToken));
assertTrue(mImeWindow.mToken.hasFixedRotationTransform());
- assertTrue(mImeWindow.isAnimating(PARENTS, ANIMATION_TYPE_FIXED_TRANSFORM));
+ assertTrue(mImeWindow.isAnimating(PARENTS, ANIMATION_TYPE_TOKEN_TRANSFORM));
// The fixed rotation transform can only be finished when all animation finished.
doReturn(false).when(app2).isAnimating(anyInt(), anyInt());
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
index 02009b75e319..47c217651e78 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
@@ -242,5 +242,10 @@ public class DisplayWindowPolicyControllerTests extends WindowTestsBase {
mRunningUids.clear();
mRunningUids.addAll(runningUids);
}
+
+ @Override
+ public boolean canShowTasksInRecents() {
+ return true;
+ }
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
index dbb7fae548b7..db3a51ca4791 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
@@ -39,6 +39,7 @@ import static com.android.server.wm.SizeCompatTests.rotateDisplay;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -168,7 +169,8 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
- prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_PORTRAIT);
+ prepareLimitedBounds(mFirstActivity, SCREEN_ORIENTATION_PORTRAIT,
+ false /* isUnresizable */);
final Rect dagBounds = new Rect(mFirstRoot.getBounds());
final Rect taskBounds = new Rect(mFirstTask.getBounds());
final Rect activityBounds = new Rect(mFirstActivity.getBounds());
@@ -209,8 +211,10 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
assertThat(activityConfigBounds.width()).isEqualTo(activityBounds.width());
assertThat(activityConfigBounds.height()).isEqualTo(activityBounds.height());
assertThat(activitySizeCompatBounds.height()).isEqualTo(newTaskBounds.height());
- assertThat(activitySizeCompatBounds.width()).isEqualTo(
- newTaskBounds.height() * newTaskBounds.height() / newTaskBounds.width());
+ final float defaultAspectRatio = mFirstActivity.mWmService.mLetterboxConfiguration
+ .getDefaultMinAspectRatioForUnresizableApps();
+ assertEquals(activitySizeCompatBounds.width(),
+ newTaskBounds.height() / defaultAspectRatio, 0.5);
}
@Test
@@ -230,8 +234,9 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
assertThat(taskBounds).isEqualTo(dagBounds);
assertThat(activityBounds.width()).isEqualTo(dagBounds.width());
- assertThat(activityBounds.height())
- .isEqualTo(dagBounds.width() * dagBounds.width() / dagBounds.height());
+ final float defaultAspectRatio = mFirstActivity.mWmService.mLetterboxConfiguration
+ .getDefaultMinAspectRatioForUnresizableApps();
+ assertEquals(activityBounds.height(), dagBounds.width() / defaultAspectRatio, 0.5);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index caa35694f6be..1708ed7d4686 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -691,6 +691,20 @@ public class RecentTasksTest extends WindowTestsBase {
}
@Test
+ public void testVisibleTasks_excludedFromRecents_nonDefaultDisplayTaskNotVisible() {
+ Task excludedTaskOnVirtualDisplay = createTaskBuilder(".excludedTaskOnVirtualDisplay")
+ .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+ .build();
+ excludedTaskOnVirtualDisplay.mUserSetupComplete = true;
+ doReturn(false).when(excludedTaskOnVirtualDisplay).isOnHomeDisplay();
+ mRecentTasks.add(mTasks.get(0));
+ mRecentTasks.add(excludedTaskOnVirtualDisplay);
+
+ // Expect that the first visible excluded-from-recents task is visible
+ assertGetRecentTasksOrder(0 /* flags */, mTasks.get(0));
+ }
+
+ @Test
public void testVisibleTasks_excludedFromRecents_withExcluded() {
// Create some set of tasks, some of which are visible and some are not
Task t1 = createTaskBuilder("com.android.pkg1", ".Task1").build();
@@ -802,6 +816,17 @@ public class RecentTasksTest extends WindowTestsBase {
}
@Test
+ public void testVisibleTask_displayCanNotShowTaskFromRecents_expectNotVisible() {
+ final DisplayContent displayContent = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
+ doReturn(false).when(displayContent).canShowTasksInRecents();
+ final Task task = displayContent.getDefaultTaskDisplayArea().createRootTask(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
+ mRecentTasks.add(task);
+
+ assertFalse(mRecentTasks.isVisibleRecentTask(task));
+ }
+
+ @Test
public void testFreezeTaskListOrder_reorderExistingTask() {
// Add some tasks
mRecentTasks.add(mTasks.get(0));
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index eba276f99225..8546763aebec 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -36,6 +36,7 @@ import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_P
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_TOKEN_TRANSFORM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -595,6 +596,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
eq(mDefaultDisplay.mDisplayId), eq(true));
verify(transaction).setLayer(navToken.getSurfaceControl(), 0);
assertFalse(mController.isNavigationBarAttachedToApp());
+ assertTrue(navToken.isAnimating(ANIMATION_TYPE_TOKEN_TRANSFORM));
}
@Test
@@ -622,6 +624,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
verify(transaction).setLayer(navToken.getSurfaceControl(), 0);
verify(transaction).reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
assertFalse(mController.isNavigationBarAttachedToApp());
+ assertFalse(navToken.isAnimating(ANIMATION_TYPE_TOKEN_TRANSFORM));
}
@Test
@@ -649,6 +652,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
eq(mDefaultDisplay.mDisplayId), eq(true));
verify(transaction).setLayer(navToken.getSurfaceControl(), 0);
assertFalse(mController.isNavigationBarAttachedToApp());
+ assertTrue(navToken.isAnimating(ANIMATION_TYPE_TOKEN_TRANSFORM));
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 0240cc315e7b..7f70882a70fc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -108,6 +108,13 @@ import org.junit.runner.RunWith;
@Presubmit
@RunWith(WindowTestRunner.class)
public class SizeCompatTests extends WindowTestsBase {
+ private static final String CONFIG_NEVER_CONSTRAIN_DISPLAY_APIS =
+ "never_constrain_display_apis";
+ private static final String CONFIG_ALWAYS_CONSTRAIN_DISPLAY_APIS =
+ "always_constrain_display_apis";
+ private static final String CONFIG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES =
+ "never_constrain_display_apis_all_packages";
+
@Rule
public TestRule compatChangeRule = new PlatformCompatChangeRule();
@@ -123,8 +130,10 @@ public class SizeCompatTests extends WindowTestsBase {
doReturn(mActivityMetricsLogger).when(mAtm.mTaskSupervisor).getActivityMetricsLogger();
mInitialConstrainDisplayApisFlags = DeviceConfig.getProperties(
NAMESPACE_CONSTRAIN_DISPLAY_APIS);
- DeviceConfig.setProperties(
- new Properties.Builder(NAMESPACE_CONSTRAIN_DISPLAY_APIS).build());
+ // Provide empty default values for the configs.
+ setNeverConstrainDisplayApisFlag("", true);
+ setNeverConstrainDisplayApisAllPackagesFlag(false, true);
+ setAlwaysConstrainDisplayApisFlag("", true);
}
@After
@@ -805,9 +814,9 @@ public class SizeCompatTests extends WindowTestsBase {
public void testNeverConstrainDisplayApisDeviceConfig_allPackagesFlagTrue_sandboxNotApplied() {
setUpDisplaySizeWithApp(1000, 1200);
- setNeverConstrainDisplayApisAllPackagesFlag("true");
+ setNeverConstrainDisplayApisAllPackagesFlag(true, false);
// Setting 'never_constrain_display_apis' as well to make sure it is ignored.
- setNeverConstrainDisplayApisFlag("com.android.other::,com.android.other2::");
+ setNeverConstrainDisplayApisFlag("com.android.other::,com.android.other2::", false);
// Make the task root resizable.
mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE;
@@ -830,7 +839,7 @@ public class SizeCompatTests extends WindowTestsBase {
setNeverConstrainDisplayApisFlag(
"com.android.frameworks.wmtests:20:,com.android.other::,"
- + "com.android.frameworks.wmtests:0:10");
+ + "com.android.frameworks.wmtests:0:10", false);
// Make the task root resizable.
mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE;
@@ -851,7 +860,8 @@ public class SizeCompatTests extends WindowTestsBase {
public void testNeverConstrainDisplayApisDeviceConfig_packageOutsideRange_sandboxingApplied() {
setUpDisplaySizeWithApp(1000, 1200);
- setNeverConstrainDisplayApisFlag("com.android.other::,com.android.frameworks.wmtests:1:5");
+ setNeverConstrainDisplayApisFlag("com.android.other::,com.android.frameworks.wmtests:1:5",
+ false);
// Make the task root resizable.
mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE;
@@ -870,7 +880,7 @@ public class SizeCompatTests extends WindowTestsBase {
public void testNeverConstrainDisplayApisDeviceConfig_packageNotInFlag_sandboxingApplied() {
setUpDisplaySizeWithApp(1000, 1200);
- setNeverConstrainDisplayApisFlag("com.android.other::,com.android.other2::");
+ setNeverConstrainDisplayApisFlag("com.android.other::,com.android.other2::", false);
// Make the task root resizable.
mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE;
@@ -952,7 +962,7 @@ public class SizeCompatTests extends WindowTestsBase {
setAlwaysConstrainDisplayApisFlag(
"com.android.frameworks.wmtests:20:,com.android.other::,"
- + "com.android.frameworks.wmtests:0:10");
+ + "com.android.frameworks.wmtests:0:10", false);
// Make the task root resizable.
mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE;
@@ -1429,12 +1439,10 @@ public class SizeCompatTests extends WindowTestsBase {
setUpDisplaySizeWithApp(2800, 1400);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
- // Portrait fixed app with min aspect ratio higher that aspect ratio override for fixed
- // orientation letterbox.
final float fixedOrientationLetterboxAspectRatio = 1.1f;
mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(
fixedOrientationLetterboxAspectRatio);
- prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
+ prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_PORTRAIT, /* isUnresizable= */ false);
final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
final Rect activityBounds = new Rect(mActivity.getBounds());
@@ -1455,6 +1463,103 @@ public class SizeCompatTests extends WindowTestsBase {
}
@Test
+ public void testDisplayIgnoreOrientationRequest_unresizableWithCorrespondingMinAspectRatio() {
+ // Set up a display in landscape and ignoring orientation request.
+ setUpDisplaySizeWithApp(2800, 1400);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ final float fixedOrientationLetterboxAspectRatio = 1.1f;
+ mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(
+ fixedOrientationLetterboxAspectRatio);
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+
+ final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
+ final Rect activityBounds = new Rect(mActivity.getBounds());
+
+ // Display shouldn't be rotated.
+ assertEquals(SCREEN_ORIENTATION_UNSPECIFIED,
+ mActivity.mDisplayContent.getLastOrientation());
+ assertTrue(displayBounds.width() > displayBounds.height());
+
+ // App should launch in fixed orientation letterbox.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFalse(mActivity.inSizeCompatMode());
+
+ // Letterbox logic should use config_letterboxDefaultMinAspectRatioForUnresizableApps over
+ // config_fixedOrientationLetterboxAspectRatio.
+ assertEquals(displayBounds.height(), activityBounds.height());
+ final float defaultAspectRatio = mActivity.mWmService.mLetterboxConfiguration
+ .getDefaultMinAspectRatioForUnresizableApps();
+ assertEquals(displayBounds.height() / defaultAspectRatio, activityBounds.width(), 0.5);
+ }
+
+ @Test
+ public void testSplitAspectRatioForUnresizablePortraitApps() {
+ // Set up a display in landscape and ignoring orientation request.
+ setUpDisplaySizeWithApp(1600, 1400);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ mActivity.mWmService.mLetterboxConfiguration
+ .setIsSplitScreenAspectRatioForUnresizableAppsEnabled(true);
+
+ mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.1f);
+
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+
+ final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
+ final Rect activityBounds = new Rect(mActivity.getBounds());
+
+ // App should launch in fixed orientation letterbox.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ // Checking that there is no size compat mode.
+ assertFitted();
+
+ assertEquals(displayBounds.height(), activityBounds.height());
+ assertTrue(activityBounds.width() < displayBounds.width() / 2);
+
+ final TestSplitOrganizer organizer =
+ new TestSplitOrganizer(mAtm, mActivity.getDisplayContent());
+ // Move activity to split screen which takes half of the screen.
+ mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test");
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode());
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode());
+ // Checking that there is no size compat mode.
+ assertFitted();
+ }
+
+ @Test
+ public void testSplitAspectRatioForUnresizableLandscapeApps() {
+ // Set up a display in landscape and ignoring orientation request.
+ setUpDisplaySizeWithApp(1400, 1600);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ mActivity.mWmService.mLetterboxConfiguration
+ .setIsSplitScreenAspectRatioForUnresizableAppsEnabled(true);
+
+ mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.1f);
+
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
+
+ final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
+ final Rect activityBounds = new Rect(mActivity.getBounds());
+
+ // App should launch in fixed orientation letterbox.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ // Checking that there is no size compat mode.
+ assertFitted();
+
+ assertEquals(displayBounds.width(), activityBounds.width());
+ assertTrue(activityBounds.height() < displayBounds.height() / 2);
+
+ final TestSplitOrganizer organizer =
+ new TestSplitOrganizer(mAtm, mActivity.getDisplayContent());
+ // Move activity to split screen which takes half of the screen.
+ mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test");
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode());
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode());
+ // Checking that there is no size compat mode.
+ assertFitted();
+ }
+
+ @Test
public void
testDisplayIgnoreOrientationRequest_orientationLetterboxBecameSizeCompatAfterRotate() {
// Set up a display in landscape and ignoring orientation request.
@@ -1928,7 +2033,7 @@ public class SizeCompatTests extends WindowTestsBase {
}
@Test
- public void testSupportsNonResizableInSplitScreen_fillTaskForSameOrientation() {
+ public void testSupportsNonResizableInSplitScreen_aspectRatioLetterboxInSameOrientation() {
// Support non resizable in multi window
mAtm.mDevEnableNonResizableMultiWindow = true;
setUpDisplaySizeWithApp(1000, 2800);
@@ -1966,7 +2071,12 @@ public class SizeCompatTests extends WindowTestsBase {
// Activity bounds fill split screen.
final Rect primarySplitBounds = new Rect(organizer.mPrimary.getBounds());
final Rect letterboxedBounds = new Rect(mActivity.getBounds());
- assertEquals(primarySplitBounds, letterboxedBounds);
+ // Activity is letterboxed for aspect ratio.
+ assertEquals(primarySplitBounds.height(), letterboxedBounds.height());
+ final float defaultAspectRatio = mActivity.mWmService.mLetterboxConfiguration
+ .getDefaultMinAspectRatioForUnresizableApps();
+ assertEquals(primarySplitBounds.height() / defaultAspectRatio,
+ letterboxedBounds.width(), 0.5);
}
@Test
@@ -2707,19 +2817,22 @@ public class SizeCompatTests extends WindowTestsBase {
displayContent.onRequestedOverrideConfigurationChanged(c);
}
- private static void setNeverConstrainDisplayApisFlag(@Nullable String value) {
- DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS, "never_constrain_display_apis",
- value, /* makeDefault= */ false);
+ private static void setNeverConstrainDisplayApisFlag(@Nullable String value,
+ boolean makeDefault) {
+ DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS,
+ CONFIG_NEVER_CONSTRAIN_DISPLAY_APIS, value, makeDefault);
}
- private static void setNeverConstrainDisplayApisAllPackagesFlag(@Nullable String value) {
+ private static void setNeverConstrainDisplayApisAllPackagesFlag(boolean value,
+ boolean makeDefault) {
DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS,
- "never_constrain_display_apis_all_packages",
- value, /* makeDefault= */ false);
+ CONFIG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES, String.valueOf(value),
+ makeDefault);
}
- private static void setAlwaysConstrainDisplayApisFlag(@Nullable String value) {
- DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS, "always_constrain_display_apis",
- value, /* makeDefault= */ false);
+ private static void setAlwaysConstrainDisplayApisFlag(@Nullable String value,
+ boolean makeDefault) {
+ DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS,
+ CONFIG_ALWAYS_CONSTRAIN_DISPLAY_APIS, value, makeDefault);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 7cdf5a8629cb..3ec24b76960f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -24,6 +24,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.testing.Assert.assertThrows;
+import static com.google.common.truth.Truth.assertWithMessage;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -42,6 +44,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
@@ -77,6 +80,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
private static final int TASK_ID = 10;
private TaskFragmentOrganizerController mController;
+ private WindowOrganizerController mWindowOrganizerController;
private TaskFragmentOrganizer mOrganizer;
private TaskFragmentOrganizerToken mOrganizerToken;
private ITaskFragmentOrganizer mIOrganizer;
@@ -86,10 +90,13 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
private WindowContainerTransaction mTransaction;
private WindowContainerToken mFragmentWindowToken;
private RemoteAnimationDefinition mDefinition;
+ private IBinder mErrorToken;
+ private Rect mTaskFragBounds;
@Before
public void setup() {
- mController = mAtm.mWindowOrganizerController.mTaskFragmentOrganizerController;
+ mWindowOrganizerController = mAtm.mWindowOrganizerController;
+ mController = mWindowOrganizerController.mTaskFragmentOrganizerController;
mOrganizer = new TaskFragmentOrganizer(Runnable::run);
mOrganizerToken = mOrganizer.getOrganizerToken();
mIOrganizer = ITaskFragmentOrganizer.Stub.asInterface(mOrganizerToken.asBinder());
@@ -100,6 +107,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
mTransaction = new WindowContainerTransaction();
mFragmentWindowToken = mTaskFragment.mRemoteToken.toWindowContainerToken();
mDefinition = new RemoteAnimationDefinition();
+ mErrorToken = new Binder();
+ final Rect displayBounds = mDisplayContent.getBounds();
+ mTaskFragBounds = new Rect(displayBounds.left, displayBounds.top, displayBounds.centerX(),
+ displayBounds.centerY());
spyOn(mController);
spyOn(mOrganizer);
@@ -220,16 +231,15 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
}
@Test
- public void testOnTaskFragmentError() throws RemoteException {
- final IBinder errorCallbackToken = new Binder();
+ public void testOnTaskFragmentError() {
final Throwable exception = new IllegalArgumentException("Test exception");
mController.registerOrganizer(mIOrganizer);
mController.onTaskFragmentError(mTaskFragment.getTaskFragmentOrganizer(),
- errorCallbackToken, exception);
+ mErrorToken, exception);
mController.dispatchPendingEvents();
- verify(mOrganizer).onTaskFragmentError(eq(errorCallbackToken), eq(exception));
+ verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), eq(exception));
}
@Test
@@ -279,7 +289,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
final int uid = Binder.getCallingUid();
mTaskFragment.setTaskFragmentOrganizer(mOrganizer.getOrganizerToken(), uid,
DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME);
- mAtm.mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
+ mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
mController.registerOrganizer(mIOrganizer);
mOrganizer.applyTransaction(mTransaction);
final Task task = createTask(mDisplayContent);
@@ -304,7 +314,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
final IBinder temporaryToken = token.getValue();
assertNotEquals(activity.token, temporaryToken);
mTransaction.reparentActivityToTaskFragment(mFragmentToken, temporaryToken);
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ mWindowOrganizerController.applyTransaction(mTransaction);
assertEquals(mTaskFragment, activity.getTaskFragment());
// The temporary token can only be used once.
@@ -394,8 +404,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// No lifecycle update when the TaskFragment is not recorded.
verify(mAtm.mRootWindowContainer, never()).resumeFocusedTasksTopActivities();
- mAtm.mWindowOrganizerController.mLaunchTaskFragments
- .put(mFragmentToken, mTaskFragment);
+ mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
assertApplyTransactionAllowed(mTransaction);
verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
@@ -465,23 +474,23 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// Fail to create TaskFragment when the task uid is different from caller.
activity.info.applicationInfo.uid = uid;
activity.getTask().effectiveUid = uid + 1;
- mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+ mWindowOrganizerController.applyTransaction(mTransaction);
- assertNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
+ assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
// Fail to create TaskFragment when the task uid is different from owner activity.
activity.info.applicationInfo.uid = uid + 1;
activity.getTask().effectiveUid = uid;
- mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+ mWindowOrganizerController.applyTransaction(mTransaction);
- assertNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
+ assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
// Successfully created a TaskFragment for same uid.
activity.info.applicationInfo.uid = uid;
activity.getTask().effectiveUid = uid;
- mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+ mWindowOrganizerController.applyTransaction(mTransaction);
- assertNotNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
+ assertNotNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
}
@Test
@@ -518,7 +527,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
.setParentTask(task)
.setFragmentToken(mFragmentToken)
.build();
- mAtm.mWindowOrganizerController.mLaunchTaskFragments
+ mWindowOrganizerController.mLaunchTaskFragments
.put(mFragmentToken, mTaskFragment);
mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token);
doReturn(true).when(mTaskFragment).isAllowedToEmbedActivity(activity);
@@ -548,8 +557,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
.setOrganizer(mOrganizer)
.createActivityCount(1)
.build();
- mAtm.mWindowOrganizerController.mLaunchTaskFragments.put(token0, tf0);
- mAtm.mWindowOrganizerController.mLaunchTaskFragments.put(token1, tf1);
+ mWindowOrganizerController.mLaunchTaskFragments.put(token0, tf0);
+ mWindowOrganizerController.mLaunchTaskFragments.put(token1, tf1);
final ActivityRecord activity0 = tf0.getTopMostActivity();
final ActivityRecord activity1 = tf1.getTopMostActivity();
@@ -557,7 +566,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
final ActivityRecord activityInOtherTask = createActivityRecord(mDefaultDisplay);
mDisplayContent.setFocusedApp(activityInOtherTask);
mTransaction.requestFocusOnTaskFragment(token0);
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ mWindowOrganizerController.applyTransaction(mTransaction);
assertEquals(activityInOtherTask, mDisplayContent.mFocusedApp);
@@ -565,7 +574,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
activity0.setState(ActivityRecord.State.PAUSED, "test");
activity1.setState(ActivityRecord.State.RESUMED, "test");
mDisplayContent.setFocusedApp(activity1);
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ mWindowOrganizerController.applyTransaction(mTransaction);
assertEquals(activity1, mDisplayContent.mFocusedApp);
@@ -573,7 +582,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// has a resumed activity.
activity0.setState(ActivityRecord.State.RESUMED, "test");
mDisplayContent.setFocusedApp(activity1);
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ mWindowOrganizerController.applyTransaction(mTransaction);
assertEquals(activity0, mDisplayContent.mFocusedApp);
}
@@ -582,53 +591,50 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
public void testTaskFragmentInPip_startActivityInTaskFragment() {
setupTaskFragmentInPip();
final ActivityRecord activity = mTaskFragment.getTopMostActivity();
- final IBinder errorToken = new Binder();
spyOn(mAtm.getActivityStartController());
- spyOn(mAtm.mWindowOrganizerController);
+ spyOn(mWindowOrganizerController);
// Not allow to start activity in a TaskFragment that is in a PIP Task.
mTransaction.startActivityInTaskFragment(
mFragmentToken, activity.token, new Intent(), null /* activityOptions */)
- .setErrorCallbackToken(errorToken);
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ .setErrorCallbackToken(mErrorToken);
+ mWindowOrganizerController.applyTransaction(mTransaction);
verify(mAtm.getActivityStartController(), never()).startActivityInTaskFragment(any(), any(),
- any(), any(), anyInt(), anyInt());
+ any(), any(), anyInt(), anyInt(), any());
verify(mAtm.mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
- eq(errorToken), any(IllegalArgumentException.class));
+ eq(mErrorToken), any(IllegalArgumentException.class));
}
@Test
public void testTaskFragmentInPip_reparentActivityToTaskFragment() {
setupTaskFragmentInPip();
final ActivityRecord activity = createActivityRecord(mDisplayContent);
- final IBinder errorToken = new Binder();
- spyOn(mAtm.mWindowOrganizerController);
+ spyOn(mWindowOrganizerController);
// Not allow to reparent activity to a TaskFragment that is in a PIP Task.
mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token)
- .setErrorCallbackToken(errorToken);
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ .setErrorCallbackToken(mErrorToken);
+ mWindowOrganizerController.applyTransaction(mTransaction);
- verify(mAtm.mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
- eq(errorToken), any(IllegalArgumentException.class));
+ verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
+ eq(mErrorToken), any(IllegalArgumentException.class));
assertNull(activity.getOrganizedTaskFragment());
}
@Test
public void testTaskFragmentInPip_setAdjacentTaskFragment() {
setupTaskFragmentInPip();
- final IBinder errorToken = new Binder();
- spyOn(mAtm.mWindowOrganizerController);
+ spyOn(mWindowOrganizerController);
// Not allow to set adjacent on a TaskFragment that is in a PIP Task.
mTransaction.setAdjacentTaskFragments(mFragmentToken, null /* fragmentToken2 */,
null /* options */)
- .setErrorCallbackToken(errorToken);
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ .setErrorCallbackToken(mErrorToken);
+ mWindowOrganizerController.applyTransaction(mTransaction);
- verify(mAtm.mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
- eq(errorToken), any(IllegalArgumentException.class));
+ verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
+ eq(mErrorToken), any(IllegalArgumentException.class));
verify(mTaskFragment, never()).setAdjacentTaskFragment(any());
}
@@ -639,47 +645,45 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
ACTIVITY_TYPE_STANDARD);
final ActivityRecord activity = createActivityRecord(pipTask);
final IBinder fragmentToken = new Binder();
- final IBinder errorToken = new Binder();
- spyOn(mAtm.mWindowOrganizerController);
+ spyOn(mWindowOrganizerController);
// Not allow to create TaskFragment in a PIP Task.
createTaskFragmentFromOrganizer(mTransaction, activity, fragmentToken);
- mTransaction.setErrorCallbackToken(errorToken);
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ mTransaction.setErrorCallbackToken(mErrorToken);
+ mWindowOrganizerController.applyTransaction(mTransaction);
- verify(mAtm.mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
- eq(errorToken), any(IllegalArgumentException.class));
- assertNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
+ verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
+ eq(mErrorToken), any(IllegalArgumentException.class));
+ assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
}
@Test
public void testTaskFragmentInPip_deleteTaskFragment() {
setupTaskFragmentInPip();
- final IBinder errorToken = new Binder();
- spyOn(mAtm.mWindowOrganizerController);
+ spyOn(mWindowOrganizerController);
// Not allow to delete a TaskFragment that is in a PIP Task.
mTransaction.deleteTaskFragment(mFragmentWindowToken)
- .setErrorCallbackToken(errorToken);
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ .setErrorCallbackToken(mErrorToken);
+ mWindowOrganizerController.applyTransaction(mTransaction);
- verify(mAtm.mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
- eq(errorToken), any(IllegalArgumentException.class));
- assertNotNull(mAtm.mWindowOrganizerController.getTaskFragment(mFragmentToken));
+ verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
+ eq(mErrorToken), any(IllegalArgumentException.class));
+ assertNotNull(mWindowOrganizerController.getTaskFragment(mFragmentToken));
// Allow organizer to delete empty TaskFragment for cleanup.
final Task task = mTaskFragment.getTask();
mTaskFragment.removeChild(mTaskFragment.getTopMostActivity());
- mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+ mWindowOrganizerController.applyTransaction(mTransaction);
- assertNull(mAtm.mWindowOrganizerController.getTaskFragment(mFragmentToken));
+ assertNull(mWindowOrganizerController.getTaskFragment(mFragmentToken));
assertNull(task.getTopChild());
}
@Test
public void testTaskFragmentInPip_setConfig() {
setupTaskFragmentInPip();
- spyOn(mAtm.mWindowOrganizerController);
+ spyOn(mWindowOrganizerController);
// Set bounds is ignored on a TaskFragment that is in a PIP Task.
mTransaction.setBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100));
@@ -831,14 +835,13 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
final IBinder fragmentToken = new Binder();
createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
- final TaskFragment taskFragment = mAtm.mWindowOrganizerController
- .getTaskFragment(fragmentToken);
+ final TaskFragment taskFragment = mWindowOrganizerController.getTaskFragment(fragmentToken);
assertNotNull(taskFragment);
taskFragment.removeImmediately();
- assertNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
+ assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
}
/**
@@ -901,6 +904,101 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
assertApplyTransactionDisallowed(mTransaction);
}
+ // TODO(b/232871351): add test for minimum dimension violation in startActivityInTaskFragment
+ @Test
+ public void testMinDimensionViolation_ReparentActivityToTaskFragment() {
+ final Task task = createTask(mDisplayContent);
+ final ActivityRecord activity = createActivityRecord(task);
+ // Make minWidth/minHeight exceeds the TaskFragment bounds.
+ activity.info.windowLayout = new ActivityInfo.WindowLayout(
+ 0, 0, 0, 0, 0, mTaskFragBounds.width() + 10, mTaskFragBounds.height() + 10);
+ mOrganizer.applyTransaction(mTransaction);
+ mController.registerOrganizer(mIOrganizer);
+ mTaskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .setFragmentToken(mFragmentToken)
+ .setOrganizer(mOrganizer)
+ .setBounds(mTaskFragBounds)
+ .build();
+ doReturn(true).when(mTaskFragment).isAllowedToEmbedActivity(activity);
+ mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
+ clearInvocations(mAtm.mRootWindowContainer);
+
+ // Reparent activity to mTaskFragment, which is smaller than activity's
+ // minimum dimensions.
+ mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token)
+ .setErrorCallbackToken(mErrorToken);
+ mWindowOrganizerController.applyTransaction(mTransaction);
+
+ verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), any(SecurityException.class));
+ }
+
+ @Test
+ public void testMinDimensionViolation_ReparentChildren() {
+ final Task task = createTask(mDisplayContent);
+ mOrganizer.applyTransaction(mTransaction);
+ mController.registerOrganizer(mIOrganizer);
+ final IBinder oldFragToken = new Binder();
+ final TaskFragment oldTaskFrag = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .createActivityCount(1)
+ .setFragmentToken(oldFragToken)
+ .setOrganizer(mOrganizer)
+ .build();
+ final ActivityRecord activity = oldTaskFrag.getTopMostActivity();
+ // Make minWidth/minHeight exceeds mTaskFragment bounds.
+ activity.info.windowLayout = new ActivityInfo.WindowLayout(
+ 0, 0, 0, 0, 0, mTaskFragBounds.width() + 10, mTaskFragBounds.height() + 10);
+ mTaskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .setFragmentToken(mFragmentToken)
+ .setOrganizer(mOrganizer)
+ .setBounds(mTaskFragBounds)
+ .build();
+ doReturn(true).when(mTaskFragment).isAllowedToEmbedActivity(activity);
+ mWindowOrganizerController.mLaunchTaskFragments.put(oldFragToken, oldTaskFrag);
+ mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
+ clearInvocations(mAtm.mRootWindowContainer);
+
+ // Reparent oldTaskFrag's children to mTaskFragment, which is smaller than activity's
+ // minimum dimensions.
+ mTransaction.reparentChildren(oldTaskFrag.mRemoteToken.toWindowContainerToken(),
+ mTaskFragment.mRemoteToken.toWindowContainerToken())
+ .setErrorCallbackToken(mErrorToken);
+ mWindowOrganizerController.applyTransaction(mTransaction);
+
+ verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), any(SecurityException.class));
+ }
+
+ @Test
+ public void testMinDimensionViolation_SetBounds() {
+ final Task task = createTask(mDisplayContent);
+ mOrganizer.applyTransaction(mTransaction);
+ mController.registerOrganizer(mIOrganizer);
+ mTaskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .createActivityCount(1)
+ .setFragmentToken(mFragmentToken)
+ .setOrganizer(mOrganizer)
+ .setBounds(new Rect(0, 0, mTaskFragBounds.right * 2, mTaskFragBounds.bottom * 2))
+ .build();
+ final ActivityRecord activity = mTaskFragment.getTopMostActivity();
+ // Make minWidth/minHeight exceeds the TaskFragment bounds.
+ activity.info.windowLayout = new ActivityInfo.WindowLayout(
+ 0, 0, 0, 0, 0, mTaskFragBounds.width() + 10, mTaskFragBounds.height() + 10);
+ mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
+ clearInvocations(mAtm.mRootWindowContainer);
+
+ // Shrink the TaskFragment to mTaskFragBounds to make its bounds smaller than activity's
+ // minimum dimensions.
+ mTransaction.setBounds(mTaskFragment.mRemoteToken.toWindowContainerToken(), mTaskFragBounds)
+ .setErrorCallbackToken(mErrorToken);
+ mWindowOrganizerController.applyTransaction(mTransaction);
+
+ assertWithMessage("setBounds must not be performed.")
+ .that(mTaskFragment.getBounds()).isEqualTo(task.getBounds());
+ }
+
/**
* Creates a {@link TaskFragment} with the {@link WindowContainerTransaction}. Calls
* {@link WindowOrganizerController#applyTransaction} to apply the transaction,
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 71387147150e..46e21f1ffdbc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -264,7 +264,7 @@ public class TaskTests extends WindowTestsBase {
// Detach from process so the activities can be removed from hierarchy when finishing.
activity1.detachFromProcess();
activity2.detachFromProcess();
- assertNull(task.performClearTop(activity1, 0 /* launchFlags */));
+ assertTrue(task.performClearTop(activity1, 0 /* launchFlags */).finishing);
assertFalse(task.hasChild());
// In real case, the task should be preserved for adding new activity.
assertTrue(task.isAttached());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index d9d819b5f00f..234bfa7ad772 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -88,7 +88,11 @@ public class TransitionTests extends WindowTestsBase {
final SurfaceControl.Transaction mMockT = mock(SurfaceControl.Transaction.class);
private Transition createTestTransition(int transitType) {
- TransitionController controller = mock(TransitionController.class);
+ TransitionTracer tracer = mock(TransitionTracer.class);
+ final TransitionController controller = new TransitionController(
+ mock(ActivityTaskManagerService.class), mock(TaskSnapshotController.class),
+ mock(TransitionTracer.class));
+
final BLASTSyncEngine sync = createTestBLASTSyncEngine();
final Transition t = new Transition(transitType, 0 /* flags */, controller, sync);
t.startCollecting(0 /* timeoutMs */);
@@ -584,7 +588,7 @@ public class TransitionTests extends WindowTestsBase {
@Test
public void testTimeout() {
final TransitionController controller = new TransitionController(mAtm,
- mock(TaskSnapshotController.class));
+ mock(TaskSnapshotController.class), mock(TransitionTracer.class));
final BLASTSyncEngine sync = new BLASTSyncEngine(mWm);
final CountDownLatch latch = new CountDownLatch(1);
// When the timeout is reached, it will finish the sync-group and notify transaction ready.
@@ -841,7 +845,8 @@ public class TransitionTests extends WindowTestsBase {
@Test
public void testIntermediateVisibility() {
final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class);
- final TransitionController controller = new TransitionController(mAtm, snapshotController);
+ final TransitionController controller = new TransitionController(mAtm, snapshotController,
+ mock(TransitionTracer.class));
final ITransitionPlayer player = new ITransitionPlayer.Default();
controller.registerTransitionPlayer(player, null /* appThread */);
final Transition openTransition = controller.createTransition(TRANSIT_OPEN);
@@ -905,7 +910,8 @@ public class TransitionTests extends WindowTestsBase {
@Test
public void testTransientLaunch() {
final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class);
- final TransitionController controller = new TransitionController(mAtm, snapshotController);
+ final TransitionController controller = new TransitionController(mAtm, snapshotController,
+ mock(TransitionTracer.class));
final ITransitionPlayer player = new ITransitionPlayer.Default();
controller.registerTransitionPlayer(player, null /* appThread */);
final Transition openTransition = controller.createTransition(TRANSIT_OPEN);
@@ -968,7 +974,8 @@ public class TransitionTests extends WindowTestsBase {
@Test
public void testNotReadyPushPop() {
final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class);
- final TransitionController controller = new TransitionController(mAtm, snapshotController);
+ final TransitionController controller = new TransitionController(mAtm, snapshotController,
+ mock(TransitionTracer.class));
final ITransitionPlayer player = new ITransitionPlayer.Default();
controller.registerTransitionPlayer(player, null /* appThread */);
final Transition openTransition = controller.createTransition(TRANSIT_OPEN);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index 1f68608d2ce6..996382782b84 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -35,6 +35,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
@@ -82,10 +83,7 @@ public class WallpaperControllerTests extends WindowTestsBase {
assertFalse(dc.mWallpaperController.canScreenshotWallpaper());
// No wallpaper WSA Surface
- WindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class),
- true, dc, true /* ownerCanManageAppTokens */);
- WindowState wallpaperWindow = createWindow(null /* parent */, TYPE_WALLPAPER,
- wallpaperWindowToken, "wallpaperWindow");
+ final WindowState wallpaperWindow = createWallpaperWindow(dc);
assertFalse(dc.mWallpaperController.canScreenshotWallpaper());
// Wallpaper with not visible WSA surface.
@@ -107,13 +105,10 @@ public class WallpaperControllerTests extends WindowTestsBase {
@Test
public void testWallpaperSizeWithFixedTransform() {
// No wallpaper
- final DisplayContent dc = createNewDisplay();
+ final DisplayContent dc = mDisplayContent;
// No wallpaper WSA Surface
- WindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class),
- true, dc, true /* ownerCanManageAppTokens */);
- WindowState wallpaperWindow = createWindow(null /* parent */, TYPE_WALLPAPER,
- wallpaperWindowToken, "wallpaperWindow");
+ final WindowState wallpaperWindow = createWallpaperWindow(dc);
WindowManager.LayoutParams attrs = wallpaperWindow.getAttrs();
Rect bounds = dc.getBounds();
@@ -153,7 +148,7 @@ public class WallpaperControllerTests extends WindowTestsBase {
final WmDisplayCutout cutout = dc.calculateDisplayCutoutForRotation(Surface.ROTATION_0);
final DisplayFrames displayFrames = new DisplayFrames(dc.getDisplayId(), new InsetsState(),
info, cutout, RoundedCorners.NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds());
- wallpaperWindowToken.applyFixedRotationTransform(info, displayFrames, config);
+ wallpaperWindow.mToken.applyFixedRotationTransform(info, displayFrames, config);
// Check that the wallpaper has the same frame in landscape than in portrait
assertEquals(Configuration.ORIENTATION_LANDSCAPE, dc.getConfiguration().orientation);
@@ -163,10 +158,7 @@ public class WallpaperControllerTests extends WindowTestsBase {
@Test
public void testWallpaperZoom() throws RemoteException {
final DisplayContent dc = mWm.mRoot.getDefaultDisplay();
- final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
- mock(IBinder.class), true, dc, true /* ownerCanManageAppTokens */);
- final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, wallpaperWindowToken,
- "wallpaperWindow");
+ final WindowState wallpaperWindow = createWallpaperWindow(dc);
wallpaperWindow.getAttrs().privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS;
@@ -189,10 +181,7 @@ public class WallpaperControllerTests extends WindowTestsBase {
@Test
public void testWallpaperZoom_shouldNotScaleWallpaper() throws RemoteException {
final DisplayContent dc = mWm.mRoot.getDefaultDisplay();
- final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
- mock(IBinder.class), true, dc, true /* ownerCanManageAppTokens */);
- final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, wallpaperWindowToken,
- "wallpaperWindow");
+ final WindowState wallpaperWindow = createWallpaperWindow(dc);
wallpaperWindow.getAttrs().privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS;
@@ -219,11 +208,7 @@ public class WallpaperControllerTests extends WindowTestsBase {
@Test
public void testWallpaperZoom_multipleCallers() {
final DisplayContent dc = mWm.mRoot.getDefaultDisplay();
- final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
- mock(IBinder.class), true, dc,
- true /* ownerCanManageAppTokens */);
- final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, wallpaperWindowToken,
- "wallpaperWindow");
+ final WindowState wallpaperWindow = createWallpaperWindow(dc);
wallpaperWindow.getAttrs().privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS;
@@ -278,37 +263,51 @@ public class WallpaperControllerTests extends WindowTestsBase {
assertEquals(WINDOWING_MODE_FULLSCREEN, token.getWindowingMode());
}
- @UseTestDisplay(addWindows = W_ACTIVITY)
@Test
public void testFixedRotationRecentsAnimatingTask() {
+ final WindowState wallpaperWindow = createWallpaperWindow(mDisplayContent);
+ final WallpaperWindowToken wallpaperToken = wallpaperWindow.mToken.asWallpaperToken();
+ final WindowState appWin = createWindow(null, TYPE_BASE_APPLICATION, "app");
+ makeWindowVisible(appWin);
+ final ActivityRecord r = appWin.mActivityRecord;
final RecentsAnimationController recentsController = mock(RecentsAnimationController.class);
- doReturn(true).when(recentsController).isWallpaperVisible(eq(mAppWindow));
+ doReturn(true).when(recentsController).isWallpaperVisible(eq(appWin));
mWm.setRecentsAnimationController(recentsController);
- mAppWindow.mActivityRecord.applyFixedRotationTransform(mDisplayContent.getDisplayInfo(),
+ r.applyFixedRotationTransform(mDisplayContent.getDisplayInfo(),
mDisplayContent.mDisplayFrames, mDisplayContent.getConfiguration());
- mAppWindow.mActivityRecord.mVisibleRequested = true;
+ // Invisible requested activity should not share its rotation transform.
+ r.mVisibleRequested = false;
mDisplayContent.mWallpaperController.adjustWallpaperWindows();
+ assertFalse(wallpaperToken.hasFixedRotationTransform());
- assertEquals(mAppWindow, mDisplayContent.mWallpaperController.getWallpaperTarget());
// Wallpaper should link the transform of its target.
- assertTrue(mAppWindow.mActivityRecord.hasFixedRotationTransform());
-
- mAppWindow.mActivityRecord.finishFixedRotationTransform();
- // Invisible requested activity should not share its rotation transform.
- mAppWindow.mActivityRecord.mVisibleRequested = false;
+ r.mVisibleRequested = true;
mDisplayContent.mWallpaperController.adjustWallpaperWindows();
+ assertEquals(appWin, mDisplayContent.mWallpaperController.getWallpaperTarget());
+ assertTrue(r.hasFixedRotationTransform());
+ assertTrue(wallpaperToken.hasFixedRotationTransform());
- assertFalse(mAppWindow.mActivityRecord.hasFixedRotationTransform());
+ // The case with shell transition.
+ registerTestTransitionPlayer();
+ final Transition t = r.mTransitionController.createTransition(TRANSIT_OPEN);
+ final ActivityRecord recents = mock(ActivityRecord.class);
+ t.collect(r.getTask());
+ r.mTransitionController.setTransientLaunch(recents, r.getTask());
+ // The activity in restore-below task should not be the target if keyguard is not locked.
+ mDisplayContent.mWallpaperController.adjustWallpaperWindows();
+ assertNotEquals(appWin, mDisplayContent.mWallpaperController.getWallpaperTarget());
+ // The activity in restore-below task should be the target if keyguard is occluded.
+ doReturn(true).when(mDisplayContent).isKeyguardLocked();
+ mDisplayContent.mWallpaperController.adjustWallpaperWindows();
+ assertEquals(appWin, mDisplayContent.mWallpaperController.getWallpaperTarget());
}
@Test
public void testWallpaperTokenVisibility() {
final DisplayContent dc = mWm.mRoot.getDefaultDisplay();
- final WallpaperWindowToken token = new WallpaperWindowToken(mWm, mock(IBinder.class),
- true, dc, true /* ownerCanManageAppTokens */);
- final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, token,
- "wallpaperWindow");
+ final WindowState wallpaperWindow = createWallpaperWindow(dc);
+ final WallpaperWindowToken token = wallpaperWindow.mToken.asWallpaperToken();
wallpaperWindow.setHasSurface(true);
// Set-up mock shell transitions
@@ -350,6 +349,13 @@ public class WallpaperControllerTests extends WindowTestsBase {
assertTrue(token.isVisible());
}
+ private WindowState createWallpaperWindow(DisplayContent dc) {
+ final WindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class),
+ true /* explicit */, dc, true /* ownerCanManageAppTokens */);
+ return createWindow(null /* parent */, TYPE_WALLPAPER, wallpaperWindowToken,
+ "wallpaperWindow");
+ }
+
private WindowState createWallpaperTargetWindow(DisplayContent dc) {
final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService)
.setTask(dc.getDefaultTaskDisplayArea().getRootHomeTask())
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index b973fca74977..50fa4cc9eb7c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -245,6 +245,12 @@ class WindowTestsBase extends SystemServiceTestsBase {
// {@link com.android.internal.R.bool.config_letterboxIsVerticalReachabilityEnabled},
// may be set on some device form factors.
mAtm.mWindowManager.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(false);
+ // Ensure aspect ratio for unresizable apps isn't overridden on any device target.
+ // {@link com.android.internal.R.bool
+ // .config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled}, may be set on some
+ // device form factors.
+ mAtm.mWindowManager.mLetterboxConfiguration
+ .setIsSplitScreenAspectRatioForUnresizableAppsEnabled(false);
checkDeviceSpecificOverridesNotApplied();
}
@@ -254,8 +260,11 @@ class WindowTestsBase extends SystemServiceTestsBase {
// Revert back to device overrides.
mAtm.mWindowManager.mLetterboxConfiguration.resetFixedOrientationLetterboxAspectRatio();
mAtm.mWindowManager.mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier();
+ mAtm.mWindowManager.mLetterboxConfiguration.resetLetterboxVerticalPositionMultiplier();
mAtm.mWindowManager.mLetterboxConfiguration.resetIsHorizontalReachabilityEnabled();
mAtm.mWindowManager.mLetterboxConfiguration.resetIsVerticalReachabilityEnabled();
+ mAtm.mWindowManager.mLetterboxConfiguration
+ .resetIsSplitScreenAspectRatioForUnresizableAppsEnabled();
}
/**
@@ -1208,6 +1217,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
@Nullable
private TaskFragmentOrganizer mOrganizer;
private IBinder mFragmentToken;
+ private Rect mBounds;
TaskFragmentBuilder(ActivityTaskManagerService service) {
mAtm = service;
@@ -1244,6 +1254,11 @@ class WindowTestsBase extends SystemServiceTestsBase {
return this;
}
+ TaskFragmentBuilder setBounds(@Nullable Rect bounds) {
+ mBounds = bounds;
+ return this;
+ }
+
TaskFragment build() {
SystemServicesTestRule.checkHoldsLock(mAtm.mGlobalLock);
@@ -1271,6 +1286,9 @@ class WindowTestsBase extends SystemServiceTestsBase {
mOrganizer.getOrganizerToken(), DEFAULT_TASK_FRAGMENT_ORGANIZER_UID,
DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME);
}
+ if (mBounds != null && !mBounds.isEmpty()) {
+ taskFragment.setBounds(mBounds);
+ }
spyOn(taskFragment);
return taskFragment;
}
diff --git a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java
index 7e3990d95915..7d5be8ea9a79 100644
--- a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java
+++ b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java
@@ -23,15 +23,23 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager.ProcessState;
+import android.app.role.OnRoleHoldersChangedListener;
+import android.app.role.RoleManager;
import android.app.usage.BroadcastResponseStats;
+import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.permission.PermissionManager;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LongArrayQueue;
import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.CollectionUtils;
import com.android.internal.util.IndentingPrintWriter;
import java.lang.annotation.Retention;
@@ -71,14 +79,33 @@ class BroadcastResponseStatsTracker {
private SparseArray<SparseArray<UserBroadcastResponseStats>> mUserResponseStats =
new SparseArray<>();
+ /**
+ * Cache of package names holding exempted roles.
+ *
+ * Contains the mapping of userId -> {roleName -> <packages>} data.
+ */
+ // TODO: Use SparseArrayMap to simplify the logic.
+ @GuardedBy("mLock")
+ private SparseArray<ArrayMap<String, List<String>>> mExemptedRoleHoldersCache =
+ new SparseArray<>();
+ private final OnRoleHoldersChangedListener mRoleHoldersChangedListener =
+ this::onRoleHoldersChanged;
+
private AppStandbyInternal mAppStandby;
private BroadcastResponseStatsLogger mLogger;
+ private RoleManager mRoleManager;
BroadcastResponseStatsTracker(@NonNull AppStandbyInternal appStandby) {
mAppStandby = appStandby;
mLogger = new BroadcastResponseStatsLogger();
}
+ void onSystemServicesReady(Context context) {
+ mRoleManager = context.getSystemService(RoleManager.class);
+ mRoleManager.addOnRoleHoldersChangedListenerAsUser(BackgroundThread.getExecutor(),
+ mRoleHoldersChangedListener, UserHandle.ALL);
+ }
+
// TODO (206518114): Move all callbacks handling to a handler thread.
void reportBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage,
UserHandle targetUser, long idForResponseEvent,
@@ -86,10 +113,19 @@ class BroadcastResponseStatsTracker {
mLogger.logBroadcastDispatchEvent(sourceUid, targetPackage, targetUser,
idForResponseEvent, timestampMs, targetUidProcState);
if (targetUidProcState <= mAppStandby.getBroadcastResponseFgThresholdState()) {
- // No need to track the broadcast response state while the target app is
+ // No need to track the broadcast response stats while the target app is
// in the foreground.
return;
}
+ if (doesPackageHoldExemptedRole(targetPackage, targetUser)) {
+ // Package holds an exempted role, so no need to track the broadcast response stats.
+ return;
+ }
+ if (doesPackageHoldExemptedPermission(targetPackage, targetUser)) {
+ // Package holds an exempted permission, so no need to track the broadcast response
+ // stats
+ return;
+ }
synchronized (mLock) {
final ArraySet<BroadcastEvent> broadcastEvents =
getOrCreateBroadcastEventsLocked(targetPackage, targetUser);
@@ -253,6 +289,62 @@ class BroadcastResponseStatsTracker {
}
}
+ boolean doesPackageHoldExemptedRole(@NonNull String packageName, @NonNull UserHandle user) {
+ final List<String> exemptedRoles = mAppStandby.getBroadcastResponseExemptedRoles();
+ synchronized (mLock) {
+ for (int i = exemptedRoles.size() - 1; i >= 0; --i) {
+ final String roleName = exemptedRoles.get(i);
+ final List<String> roleHolders = getRoleHoldersLocked(roleName, user);
+ if (CollectionUtils.contains(roleHolders, packageName)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ boolean doesPackageHoldExemptedPermission(@NonNull String packageName,
+ @NonNull UserHandle user) {
+ final List<String> exemptedPermissions = mAppStandby
+ .getBroadcastResponseExemptedPermissions();
+ for (int i = exemptedPermissions.size() - 1; i >= 0; --i) {
+ final String permissionName = exemptedPermissions.get(i);
+ if (PermissionManager.checkPackageNamePermission(permissionName, packageName,
+ user.getIdentifier()) == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @GuardedBy("mLock")
+ @Nullable
+ private List<String> getRoleHoldersLocked(@NonNull String roleName, @NonNull UserHandle user) {
+ ArrayMap<String, List<String>> roleHoldersForUser = mExemptedRoleHoldersCache.get(
+ user.getIdentifier());
+ if (roleHoldersForUser == null) {
+ roleHoldersForUser = new ArrayMap<>();
+ mExemptedRoleHoldersCache.put(user.getIdentifier(), roleHoldersForUser);
+ }
+ List<String> roleHolders = roleHoldersForUser.get(roleName);
+ if (roleHolders == null && mRoleManager != null) {
+ roleHolders = mRoleManager.getRoleHoldersAsUser(roleName, user);
+ roleHoldersForUser.put(roleName, roleHolders);
+ }
+ return roleHolders;
+ }
+
+ private void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
+ synchronized (mLock) {
+ final ArrayMap<String, List<String>> roleHoldersForUser =
+ mExemptedRoleHoldersCache.get(user.getIdentifier());
+ if (roleHoldersForUser == null) {
+ return;
+ }
+ roleHoldersForUser.remove(roleName);
+ }
+ }
+
void onUserRemoved(@UserIdInt int userId) {
synchronized (mLock) {
mUserBroadcastEvents.remove(userId);
@@ -260,6 +352,7 @@ class BroadcastResponseStatsTracker {
for (int i = mUserResponseStats.size() - 1; i >= 0; --i) {
mUserResponseStats.valueAt(i).remove(userId);
}
+ mExemptedRoleHoldersCache.remove(userId);
}
}
@@ -373,6 +466,8 @@ class BroadcastResponseStatsTracker {
ipw.println();
dumpResponseStatsLocked(ipw);
ipw.println();
+ dumpRoleHoldersLocked(ipw);
+ ipw.println();
mLogger.dumpLogs(ipw);
}
@@ -417,5 +512,32 @@ class BroadcastResponseStatsTracker {
}
ipw.decreaseIndent();
}
+
+ @GuardedBy("mLock")
+ private void dumpRoleHoldersLocked(@NonNull IndentingPrintWriter ipw) {
+ ipw.println("Role holders:");
+ ipw.increaseIndent();
+ for (int userIdx = 0; userIdx < mExemptedRoleHoldersCache.size(); ++userIdx) {
+ final int userId = mExemptedRoleHoldersCache.keyAt(userIdx);
+ final ArrayMap<String, List<String>> roleHoldersForUser =
+ mExemptedRoleHoldersCache.valueAt(userIdx);
+ ipw.println("User " + userId + ":");
+ ipw.increaseIndent();
+ for (int roleIdx = 0; roleIdx < roleHoldersForUser.size(); ++roleIdx) {
+ final String roleName = roleHoldersForUser.keyAt(roleIdx);
+ final List<String> holders = roleHoldersForUser.valueAt(roleIdx);
+ ipw.print(roleName + ": ");
+ for (int holderIdx = 0; holderIdx < holders.size(); ++holderIdx) {
+ if (holderIdx > 0) {
+ ipw.print(", ");
+ }
+ ipw.print(holders.get(holderIdx));
+ }
+ ipw.println();
+ }
+ ipw.decreaseIndent();
+ }
+ ipw.decreaseIndent();
+ }
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 078177b3a89f..ef13cd964f6c 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -357,6 +357,7 @@ public class UsageStatsService extends SystemService implements
getDpmInternal();
// initialize mShortcutServiceInternal
getShortcutServiceInternal();
+ mResponseStatsTracker.onSystemServicesReady(getContext());
if (ENABLE_KERNEL_UPDATES && KERNEL_COUNTER_FILE.exists()) {
try {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 055864834b3b..39a6868169a7 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -70,6 +70,7 @@ import com.android.internal.app.IHotwordRecognitionStatusCallback;
import com.android.internal.app.IVoiceActionCheckCallback;
import com.android.internal.app.IVoiceInteractionSessionShowCallback;
import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.wm.ActivityAssistInfo;
import com.android.server.wm.ActivityTaskManagerInternal;
@@ -86,10 +87,14 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
final static String CLOSE_REASON_VOICE_INTERACTION = "voiceinteraction";
+ /** The delay time for retrying to request DirectActions. */
+ private static final long REQUEST_DIRECT_ACTIONS_RETRY_TIME_MS = 200;
+
final boolean mValid;
final Context mContext;
final Handler mHandler;
+ final Handler mDirectActionsHandler;
final VoiceInteractionManagerService.VoiceInteractionManagerServiceStub mServiceStub;
final int mUser;
final ComponentName mComponent;
@@ -184,6 +189,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
int userHandle, ComponentName service) {
mContext = context;
mHandler = handler;
+ mDirectActionsHandler = new Handler(true);
mServiceStub = stub;
mUser = userHandle;
mComponent = service;
@@ -343,7 +349,10 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
.getAttachedNonFinishingActivityForTask(taskId, null);
if (tokens == null || tokens.getAssistToken() != assistToken) {
Slog.w(TAG, "Unknown activity to query for direct actions");
- callback.sendResult(null);
+ mDirectActionsHandler.sendMessageDelayed(PooledLambda.obtainMessage(
+ VoiceInteractionManagerServiceImpl::retryRequestDirectActions,
+ VoiceInteractionManagerServiceImpl.this, token, taskId, assistToken,
+ cancellationCallback, callback), REQUEST_DIRECT_ACTIONS_RETRY_TIME_MS);
} else {
try {
tokens.getApplicationThread().requestDirectActions(tokens.getActivityToken(),
@@ -355,6 +364,33 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
}
}
+ private void retryRequestDirectActions(@NonNull IBinder token, int taskId,
+ @NonNull IBinder assistToken, @Nullable RemoteCallback cancellationCallback,
+ @NonNull RemoteCallback callback) {
+ synchronized (mServiceStub) {
+ if (mActiveSession == null || token != mActiveSession.mToken) {
+ Slog.w(TAG, "retryRequestDirectActions does not match active session");
+ callback.sendResult(null);
+ return;
+ }
+ final ActivityTokens tokens = LocalServices.getService(
+ ActivityTaskManagerInternal.class)
+ .getAttachedNonFinishingActivityForTask(taskId, null);
+ if (tokens == null || tokens.getAssistToken() != assistToken) {
+ Slog.w(TAG, "Unknown activity to query for direct actions during retrying");
+ callback.sendResult(null);
+ } else {
+ try {
+ tokens.getApplicationThread().requestDirectActions(tokens.getActivityToken(),
+ mActiveSession.mInteractor, cancellationCallback, callback);
+ } catch (RemoteException e) {
+ Slog.w("Unexpected remote error", e);
+ callback.sendResult(null);
+ }
+ }
+ }
+ }
+
void performDirectActionLocked(@NonNull IBinder token, @NonNull String actionId,
@Nullable Bundle arguments, int taskId, IBinder assistToken,
@Nullable RemoteCallback cancellationCallback,
diff --git a/telephony/java/android/telephony/UiccCardInfo.java b/telephony/java/android/telephony/UiccCardInfo.java
index 249f740c482b..e5e8f0a41048 100644
--- a/telephony/java/android/telephony/UiccCardInfo.java
+++ b/telephony/java/android/telephony/UiccCardInfo.java
@@ -162,7 +162,8 @@ public final class UiccCardInfo implements Parcelable {
@Deprecated
public String getIccId() {
if (mIccIdAccessRestricted) {
- throw new UnsupportedOperationException("getIccId from UiccPortInfo");
+ throw new UnsupportedOperationException("getIccId() is not supported by UiccCardInfo."
+ + " Please Use UiccPortInfo API instead");
}
//always return ICCID from first port.
return getPorts().stream().findFirst().get().getIccId();
diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java
index dd3639a9a7b9..06c5b5cfeda1 100644
--- a/telephony/java/android/telephony/UiccSlotInfo.java
+++ b/telephony/java/android/telephony/UiccSlotInfo.java
@@ -161,7 +161,8 @@ public class UiccSlotInfo implements Parcelable {
@Deprecated
public boolean getIsActive() {
if (mLogicalSlotAccessRestricted) {
- throw new UnsupportedOperationException("get port status from UiccPortInfo");
+ throw new UnsupportedOperationException("getIsActive() is not supported by "
+ + "UiccSlotInfo. Please Use UiccPortInfo API instead");
}
//always return status from first port.
return getPorts().stream().findFirst().get().isActive();
@@ -198,7 +199,8 @@ public class UiccSlotInfo implements Parcelable {
@Deprecated
public int getLogicalSlotIdx() {
if (mLogicalSlotAccessRestricted) {
- throw new UnsupportedOperationException("get logical slot index from UiccPortInfo");
+ throw new UnsupportedOperationException("getLogicalSlotIdx() is not supported by "
+ + "UiccSlotInfo. Please use UiccPortInfo API instead");
}
//always return logical slot index from first port.
//portList always have at least one element.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
index 78aea1f1fb17..933a3a0458ee 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
@@ -23,16 +23,16 @@ import android.view.Surface
import android.view.WindowManagerPolicyConstants
import androidx.test.filters.FlakyTest
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.tapl.LauncherInstrumentation
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarLayerPositionEnd
import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
@@ -43,7 +43,8 @@ import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
/**
- * Test IME window layer will become visible when switching from the fixed orientation activity.
+ * Test IME window layer will become visible when switching from the fixed orientation activity
+ * (e.g. Launcher activity).
* To run this test: `atest FlickerTests:OpenImeWindowFromFixedOrientationAppTest`
*/
@RequiresDevice
@@ -53,24 +54,31 @@ import org.junit.runners.Parameterized
@Group2
class OpenImeWindowFromFixedOrientationAppTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- private val fixedOrientationApp = FixedOrientationAppHelper(instrumentation)
private val imeTestApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
+ private val taplInstrumentation = LauncherInstrumentation()
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
setup {
+ test {
+ // Launch the activity with expecting IME will be shown.
+ imeTestApp.launchViaIntent(wmHelper)
+ }
eachRun {
- fixedOrientationApp.launchViaIntent(wmHelper)
- this.setRotation(Surface.ROTATION_90)
+ // Swiping out the IME activity to home.
+ taplInstrumentation.goHome()
+ wmHelper.waitForHomeActivityVisible()
}
}
transitions {
+ // Bring the exist IME activity to the front in landscape mode device rotation.
+ setRotation(Surface.ROTATION_90)
imeTestApp.launchViaIntent(wmHelper)
}
teardown {
test {
- fixedOrientationApp.exit(wmHelper)
+ imeTestApp.exit(wmHelper)
}
}
}
@@ -90,7 +98,7 @@ class OpenImeWindowFromFixedOrientationAppTest(private val testSpec: FlickerTest
@Presubmit
@Test
- fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
+ fun navBarLayerRotatesAndScales() = testSpec.navBarLayerPositionEnd()
@FlakyTest(bugId = 206753786)
fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
@@ -112,7 +120,7 @@ class OpenImeWindowFromFixedOrientationAppTest(private val testSpec: FlickerTest
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(
repetitions = 3,
- supportedRotations = listOf(Surface.ROTATION_0),
+ supportedRotations = listOf(Surface.ROTATION_90),
supportedNavigationModes = listOf(
WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
)
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 43aa4b151548..3e2130dc480f 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -45,6 +45,7 @@
android:theme="@style/CutoutShortEdges"
android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivityAutoFocus"
android:windowSoftInputMode="stateVisible"
+ android:configChanges="orientation|screenSize"
android:label="ImeAppAutoFocus"
android:exported="true">
<intent-filter>